development

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

big-blog 2020. 4. 16. 08:19
반응형

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


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

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

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

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

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


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());
    }
}

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());
   }
};

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 .


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() {

  }
}

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

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 코드는 실행되지 않습니다.


복잡한 방법은 org.junit.runners.BlockJUnit4ClassRunner를 서브 클래 싱하여 자신의 러너를 만드는 것입니다.

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

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) 주석을 추가해야합니다. 또는 매번 기억하지 않으려면 테스트 수퍼 클래스에 해당 주석을 넣을 수 있습니다. 물론 이것은 러너 선택을 제한하지만 허용 될 수 있습니다.

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


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


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) {
    }
}

이전 의견과 추가 고려 사항을 바탕으로 다음과 같이 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());
}
}

즐겨!


@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 );
    }
};

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


사용이 달성 할 수 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());
    }
};

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());
}

참고 URL : https://stackoverflow.com/questions/473401/get-name-of-currently-executing-test-in-junit-4

반응형