JUnit 4에서 현재 실행중인 테스트 이름 가져 오기


240

JUnit 3에서 다음과 같이 현재 실행중인 테스트 이름을 얻을 수 있습니다.

public class MyTest extends TestCase
{
    public void testSomething()
    {
        System.out.println("Current test is " + getName());
        ...
    }
}

"현재 테스트는 testSomething"입니다.

JUnit 4에서 즉시 사용 가능한 간단한 방법이 있습니까?

배경 : 테스트 이름 만 인쇄하고 싶지는 않습니다. 테스트와 이름이 같은 리소스에 저장된 테스트 특정 데이터를로드하고 싶습니다. 당신은 구성 과 그 이상에 대한 관습을 알고 있습니다.


위 코드는 JUnit 4에서 무엇을 제공합니까?
Bill the Lizard

5
JUnit 3 테스트는 getName ()이 정의 된 TestCase를 확장합니다. JUnit 4 테스트는 기본 클래스를 확장하지 않으므로 getName () 메소드가 전혀 없습니다.
Dave Ray

나에게 번호가 매겨진 테스트 사례를 제공하는 Parametrized 러너를 사용하고 있기 때문에 테스트 이름을 <b> 설정 </ b>하려는 비슷한 문제가 있습니다.
Volker Stolz

Test 또는 TestWatcher를 사용하는 멋진 솔루션 ...이 필요가 있는지 궁금해합니까? Gradle에서 제공하는 타이밍 출력 차트를 보면 테스트가 느리게 실행되고 있는지 확인할 수 있습니다. 테스트가 수행되는 순서를 알 필요가 없습니다 ...?
마이크 설치류

답변:


378

JUnit 4.7은 TestName-Rule을 사용하는 것처럼 보이는이 기능을 추가했습니다 . 다음과 같이 메소드 이름이 표시됩니다.

import org.junit.Rule;

public class NameRuleTest {
    @Rule public TestName name = new TestName();

    @Test public void testA() {
        assertEquals("testA", name.getMethodName());
    }

    @Test public void testB() {
        assertEquals("testB", name.getMethodName());
    }
}

4
또한 @before에서는 TestName을 사용할 수 없습니다. (참조 : old.nabble.com/…
jm.

41
분명히의 JUnit의 최신 버전은 실행 @Rule하기 전에 @Before내가 JUnit을에 새로 온 사람과에 따라 한 - TestName내을에 @Before어려움없이.
MightyE


2
매개 변수가있는 테스트를 사용하는 경우 "name.getMethodName ()"은 {testA [0], testA [1] 등}을 반환하므로 다음과 같이 사용합니다. assertTrue (name.getMethodName (). matches ( "testA (\ [\ \디\])?"));
Legna

2
@DuncanJones 제안 된 대안이 "더 효율적인"이유는 무엇입니까?
Stephan

117

JUnit 4.9.x 이상

JUnit 4.9부터 클래스는 호출 TestWatchman이 있는 클래스를 위해 더 이상 사용되지 않습니다 TestWatcher.

@Rule
public TestRule watcher = new TestWatcher() {
   protected void starting(Description description) {
      System.out.println("Starting test: " + description.getMethodName());
   }
};

참고 : 포함 클래스를 선언해야합니다 public.

JUnit 4.7.x-4.8.x

다음 접근법은 클래스의 모든 테스트에 대한 메소드 이름을 인쇄합니다.

@Rule
public MethodRule watchman = new TestWatchman() {
   public void starting(FrameworkMethod method) {
      System.out.println("Starting test: " + method.getName());
   }
};

1
@takacsot 놀랍습니다. 이것에 대한 새로운 질문을 게시하고 여기에 링크를 핑 할 수 있습니까?
Duncan Jones

public필드를 사용 합니까?
Raffi Khatchadourian


16

JUnit 5 이상

JUnit 5 에서는 TestInfo테스트 메소드에 제공하는 테스트 메타 데이터를 단순화 하는 것을 주입 할 수 있습니다 . 예를 들면 다음과 같습니다.

@Test
@DisplayName("This is my test")
@Tag("It is my tag")
void test1(TestInfo testInfo) {
    assertEquals("This is my test", testInfo.getDisplayName());
    assertTrue(testInfo.getTags().contains("It is my tag"));
}

더보기 : JUnit 5 사용자 안내서 , TestInfo javadoc .


9

대신 이것을 시도하십시오 :

public class MyTest {
        @Rule
        public TestName testName = new TestName();

        @Rule
        public TestWatcher testWatcher = new TestWatcher() {
            @Override
            protected void starting(final Description description) {
                String methodName = description.getMethodName();
                String className = description.getClassName();
                className = className.substring(className.lastIndexOf('.') + 1);
                System.err.println("Starting JUnit-test: " + className + " " + methodName);
            }
        };

        @Test
        public void testA() {
                assertEquals("testA", testName.getMethodName());
        }

        @Test
        public void testB() {
                assertEquals("testB", testName.getMethodName());
        }
}

결과는 다음과 같습니다.

Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB

참고 : 테스트가 TestCase 의 하위 클래스 인 경우에는 작동하지 않습니다 ! 테스트는 실행되지만 @Rule 코드는 실행되지 않습니다.


3
모범을 보이신 여러분의 노트에 대해 신의 축복을 빕니다.
user655419

"이것은 작동하지 않습니다"-요점-오이는 @Rule 주석을 무시합니다
Benjineer

8

SLF4J (Simple Logging Facade for Java) 사용은 매개 변수화 된 메시지를 사용하여 깔끔하게 개선되었습니다. SLF4J를 JUnit 4 규칙 구현과 결합하면보다 효율적인 테스트 클래스 로깅 기술을 제공 할 수 있습니다.

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingTest {

  @Rule public MethodRule watchman = new TestWatchman() {
    public void starting(FrameworkMethod method) {
      logger.info("{} being run...", method.getName());
    }
  };

  final Logger logger =
    LoggerFactory.getLogger(LoggingTest.class);

  @Test
  public void testA() {

  }

  @Test
  public void testB() {

  }
}

6

복잡한 방법은 org.junit.runners.BlockJUnit4ClassRunner를 서브 클래 싱하여 자신의 Runner를 작성하는 것입니다.

그런 다음 다음과 같은 작업을 수행 할 수 있습니다.

public class NameAwareRunner extends BlockJUnit4ClassRunner {

    public NameAwareRunner(Class<?> aClass) throws InitializationError {
        super(aClass);
    }

    @Override
    protected Statement methodBlock(FrameworkMethod frameworkMethod) {
        System.err.println(frameworkMethod.getName());
        return super.methodBlock(frameworkMethod);
    }
}

그런 다음 각 테스트 클래스마다 @RunWith (NameAwareRunner.class) 주석을 추가해야합니다. 또는 매번 기억하지 않으려면 테스트 수퍼 클래스에 주석을 넣을 수 있습니다. 물론 이것은 러너 선택을 제한하지만 허용 될 수 있습니다.

또한 현재 테스트 이름을 러너에서 프레임 워크로 가져 오는 데 약간의 쿵푸가 필요할 수 있지만 최소한 이름을 얻습니다.


개념적으로 적어도이 아이디어는 나에게 간단 해 보인다. 내 요점은 : 나는 그것을 복잡하다고 부르지 않을 것입니다.
user98761

"테스트 수퍼 클래스에서 ..."-더 이상 끔찍한 상속 기반 디자인 패턴은 없습니다. 이것은 JUnit3입니다!
11:00에

3

JUnit 4에는 테스트 케이스가 자체 이름을 얻을 수있는 기본 제공 메커니즘이 없습니다 (설정 및 해제 중 포함).


1
스택을 검사하는 것 외에 즉시 사용 가능한 메커니즘이 있습니까?
Dave Ray

4
아래 답변이 주어진 경우는 아닙니다! 다른 사람에게 정답을 할당 할 수 있습니까?
Toby

3
String testName = null;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for (int i = trace.length - 1; i > 0; --i) {
    StackTraceElement ste = trace[i];
    try {
        Class<?> cls = Class.forName(ste.getClassName());
        Method method = cls.getDeclaredMethod(ste.getMethodName());
        Test annotation = method.getAnnotation(Test.class);
        if (annotation != null) {
            testName = ste.getClassName() + "." + ste.getMethodName();
            break;
        }
    } catch (ClassNotFoundException e) {
    } catch (NoSuchMethodException e) {
    } catch (SecurityException e) {
    }
}

1
나는 그가 단지 해결책을 보여주고 싶었다고 주장 할 수있다. 왜 부정적인 투표를했는지 모르겠다 .... @downvoter : 적어도, 유용한 정보를 추가하라 ..
Victor

1
@skaffman 우리는 모든 대안 솔루션을보고 싶어합니다. 이것은 내가 찾고있는 것에 가장 가까운 것입니다 : 테스트 클래스에서 직접 테스트하지 않고 테스트 중에 사용되는 클래스 (예 : 로거 구성 요소)에서 테스트 이름 가져 오기. 테스트 관련 주석은 더 이상 작동하지 않습니다.
Daniel Alder

3

이전 의견과 추가 고려 사항을 바탕으로 다음과 같이 JUnit 테스트 방법에서 사용할 수있는 TestWather 확장을 만들었습니다.

public class ImportUtilsTest {
    private static final Logger LOGGER = Logger.getLogger(ImportUtilsTest.class);

    @Rule
    public TestWatcher testWatcher = new JUnitHelper(LOGGER);

    @Test
    public test1(){
    ...
    }
}

테스트 도우미 클래스는 다음입니다.

public class JUnitHelper extends TestWatcher {
private Logger LOGGER;

public JUnitHelper(Logger LOGGER) {
    this.LOGGER = LOGGER;
}

@Override
protected void starting(final Description description) {
    LOGGER.info("STARTED " + description.getMethodName());
}

@Override
protected void succeeded(Description description) {
    LOGGER.info("SUCCESSFUL " + description.getMethodName());
}

@Override
protected void failed(Throwable e, Description description) {
    LOGGER.error("FAILURE " + description.getMethodName());
}
}

즐겨!


안녕하세요 ImportUtilsTest, 오류가 발생했습니다. 로거 클래스 인 것 같습니다. 자세한 정보가 있습니까? 감사합니다
Sylhare

1
명명 된 클래스는 JUnit 테스트 클래스의 예일뿐입니다. JUnitHelper의 사용자입니다. 사용 예를 수정하겠습니다.
Csaba Tenkes 1

아 이제는 바보 같아요, 너무 분명했다. 고마워요! ;)
Sylhare

1
@ClassRule
public static TestRule watchman = new TestWatcher() {
    @Override
    protected void starting( final Description description ) {
        String mN = description.getMethodName();
        if ( mN == null ) {
            mN = "setUpBeforeClass..";
        }

        final String s = StringTools.toString( "starting..JUnit-Test: %s.%s", description.getClassName(), mN );
        System.err.println( s );
    }
};

0

테스트 데이터 세트에서 테스트 메소드 이름을 분리하는 것이 좋습니다. 리소스에서 테스트 데이터 세트를로드 / 캐시하는 DataLoaderFactory 클래스를 모델링 한 다음 테스트 케이스 캠에서 테스트 케이스에 대한 테스트 데이터 세트를 리턴하는 인터페이스 메소드를 호출합니다. 테스트 방법 이름에 테스트 데이터가 연결되어 있다고 가정하면 테스트 데이터를 한 번만 사용할 수 있다고 가정합니다. 대부분의 경우 비즈니스 로직의 다양한 측면을 확인하기 위해 여러 테스트에서 동일한 테스트 데이터를 사용하는 것이 좋습니다.


0

사용이 달성 할 수 Slf4jTestWatcher

private static Logger _log = LoggerFactory.getLogger(SampleTest.class.getName());

@Rule
public TestWatcher watchman = new TestWatcher() {
    @Override
    public void starting(final Description method) {
        _log.info("being run..." + method.getMethodName());
    }
};

0

JUnit 5에서 TestInfo 에서 JUnit 4의 TestName 규칙을 대체하는 역할을합니다.

설명서에서 :

TestInfo는 현재 테스트 또는 컨테이너에 대한 정보를 @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll 및 @AfterAll 메소드에 주입하는 데 사용됩니다.

현재 실행 된 테스트의 메소드 이름을 검색하려면, 두 가지 옵션이 있습니다 : String TestInfo.getDisplayName()Method TestInfo.getTestMethod() .

TestInfo.getDisplayName()테스트 방법의 기본 표시 이름이이므로 현재 테스트 방법의 이름 만 검색하는 것만으로는 충분하지 않을 수 있습니다 methodName(TypeArg1, TypeArg2, ... TypeArg3).
에 메소드 이름 복제@DisplayName("..") 하는 것은 좋은 생각이 아닙니다.

대안 TestInfo.getTestMethod()으로 Optional<Method>객체 를 반환 할 수 있습니다 .
검색 방법이 테스트 방법 내에서 사용되는 경우 Optional랩핑 된 값 을 테스트 할 필요조차 없습니다 .

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;

@Test
void doThat(TestInfo testInfo) throws Exception {
    Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
    Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}

0

ExtensionContext를 통한 JUnit 5

이점:

ExtensionContext재정 의하여 추가 기능을 사용할 수 afterEach(ExtensionContext context)있습니다.

public abstract class BaseTest {

    protected WebDriver driver;

    @RegisterExtension
    AfterEachExtension afterEachExtension = new AfterEachExtension();

    @BeforeEach
    public void beforeEach() {
        // Initialise driver
    }

    @AfterEach
    public void afterEach() {
        afterEachExtension.setDriver(driver);
    }

}
public class AfterEachExtension implements AfterEachCallback {

    private WebDriver driver;

    public void setDriver(WebDriver driver) {
        this.driver = driver;
    }

    @Override
    public void afterEach(ExtensionContext context) {
        String testMethodName = context.getTestMethod().orElseThrow().getName();
        // Attach test steps, attach scsreenshots on failure only, etc.
        driver.quit();
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.