1. 개요

단위 테스트를 할 때 주기적으로 테스트 메서드 실행 결과를 처리하기를 원할 수 있습니다. 이 빠른 사용방법(예제)에서는 JUnit에서 제공하는 TestWatcher API를 사용하여 이를 수행하는 방법을 살펴보겠습니다 .

JUnit을 사용한 테스트에 대한 심층적인 사용방법(예제)는 훌륭한 JUnit 5 사용방법(예제)를 확인하세요 .

2. TestWatcher API

간단히 말해서 TestWatcher 인터페이스는 테스트 결과를 처리하려는 확장에 대한 API를 정의합니다 . 이 API를 생각할 수 있는 한 가지 방법은 개별 테스트 케이스의 상태를 가져오기 위한 후크를 제공하는 것입니다.

그러나 실제 예를 살펴 보기 전에 한 걸음 물러나서 TestWatcher 인터페이스 의 메서드를 간략하게 요약해 보겠습니다 .

  • testAborted​(ExtensionContext context, Throwable cause)

    중단된 테스트의 결과를 처리하기 위해 testAborted 메소드를 재정의할 수 있습니다 . 이름에서 알 수 있듯이 이 메서드는 테스트가 중단된 후에 호출됩니다.

  • testDisabled​(ExtensionContext context, Optional reason)

    비활성화된 테스트 메서드의 결과를 처리하려는 경우 testDisabled 메서드를 재정의할 수 있습니다 . 이 방법에는 테스트가 비활성화된 이유도 포함될 수 있습니다.

  • testFailed(ExtensionContext context, Throwable cause)

    테스트 실패 후 추가 처리를 수행하려면 testFailed 메서드 에서 기능을 구현하면 됩니다 . 이 방법에는 테스트 실패의 원인이 포함될 수 있습니다.

  • testSuccessful(ExtensionContext context)

    마지막으로 성공적인 테스트 결과를 처리하려면 testSuccessful 메서드 를 재정의하면 됩니다 .

모든 메소드에는 ExtensionContext가 포함되어 있다는 점에 유의해야 합니다 . 이것은 현재 테스트가 실행된 컨텍스트를 캡슐화합니다.

3. 메이븐 의존성

우선, 예제에 필요한 프로젝트 의존성을 추가해 보겠습니다.
기본 JUnit 5 라이브러리 junit-jupiter-engine 외에도 junit-jupiter-api 라이브러리 도 필요합니다 .

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.4.2</version>
    <scope>test</scope>
</dependency>

항상 그렇듯이 Maven Central 에서 최신 버전을 얻을 수 있습니다 .

4. TestResultLoggerExtension 예제

이제 TestWatcher API에 대한 기본적인 이해를 하였으므로 실제 예제를 살펴보겠습니다.

결과를 기록하고 테스트 요약을 제공하기 위한 간단한 확장을 만드는 것으로 시작하겠습니다 . 이 경우 확장을 생성하려면 TestWatcher 인터페이스 를 구현하는 클래스를 정의해야 합니다 .

public class TestResultLoggerExtension implements TestWatcher, AfterAllCallback {
    private List<TestResultStatus> testResultsStatus = new ArrayList<>();

    private enum TestResultStatus {
        SUCCESSFUL, ABORTED, FAILED, DISABLED;
    }

    //...
}

모든 확장 인터페이스와 마찬가지로 TestWatcher 인터페이스는 마커 인터페이스일 뿐인 기본 확장 인터페이스 도 확장합니다 . 이 예에서는 AfterAllCallback 인터페이스 도 구현합니다 .

확장 프로그램 에는 테스트 결과의 상태를 나타내는 데 사용할 간단한 열거 TestResultStatus List이 있습니다.

4.1. 테스트 결과 처리

이제 개별 단위 테스트 방법의 결과를 처리하는 방법을 살펴보겠습니다.

@Override
public void testDisabled(ExtensionContext context, Optional<String> reason) {
    LOG.info("Test Disabled for test {}: with reason :- {}", 
      context.getDisplayName(),
      reason.orElse("No reason"));

    testResultsStatus.add(TestResultStatus.DISABLED);
}

@Override
public void testSuccessful(ExtensionContext context) {
    LOG.info("Test Successful for test {}: ", context.getDisplayName());

    testResultsStatus.add(TestResultStatus.SUCCESSFUL);
}  

확장의 본문을 채우고 testDisabled()testSuccessful() 메서드를 재정의하는 것으로 시작 합니다 .

간단한 예제에서는 테스트 이름을 출력하고 테스트 상태를 testResultsStatus List 추가 합니다.

testAborted()testFailed() 의 다른 두 가지 방법에 대해 이 방식으로 계속 진행합니다 .

@Override
public void testAborted(ExtensionContext context, Throwable cause) {
    LOG.info("Test Aborted for test {}: ", context.getDisplayName());

    testResultsStatus.add(TestResultStatus.ABORTED);
}

@Override
public void testFailed(ExtensionContext context, Throwable cause) {
    LOG.info("Test Failed for test {}: ", context.getDisplayName());

    testResultsStatus.add(TestResultStatus.FAILED);
}

4.2. 테스트 결과 요약

예제의 마지막 부분 에서 afterAll() 메서드를 재정의합니다 .

@Override
public void afterAll(ExtensionContext context) throws Exception {
    Map<TestResultStatus, Long> summary = testResultsStatus.stream()
      .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    LOG.info("Test result summary for {} {}", context.getDisplayName(), summary.toString());
}

빠르게 요약하자면 모든 테스트 메서드가 실행된 후 afterAll 메서드가 실행됩니다. 이 방법을 사용 하여 매우 기본적인 요약을 출력하기 전에 테스트 결과 List에 있는 다른 TestResultStatus 를 그룹화합니다 .

수명 주기 콜백에 대한 심층 사용방법(예제)는 JUnit 5 확장에 대한 훌륭한 사용방법(예제)를 확인하세요 .

5. 테스트 실행

이 끝에서 두 번째 섹션에서는 간단한 로깅 확장을 사용하여 테스트의 출력이 어떻게 보이는지 확인할 것입니다.

확장을 정의했으므로 먼저 표준 @ExtendWith 어노테이션을 사용하여 확장을 등록합니다 .

@ExtendWith(TestResultLoggerExtension.class)
class TestWatcherAPIUnitTest {

    @Test
    void givenFalseIsTrue_whenTestAbortedThenCaptureResult() {
        Assumptions.assumeTrue(false);
    }

    @Disabled
    @Test
    void givenTrueIsTrue_whenTestDisabledThenCaptureResult() {
        Assert.assertTrue(true);
    }

    //...

다음으로, 비활성화된 테스트, 중단된 테스트 및 성공적인 테스트를 혼합하여 테스트 클래스를 단위 테스트로 채웁니다.

5.1. 출력 검토

단위 테스트를 실행할 때 각 테스트의 출력을 확인해야 합니다.

INFO  c.b.e.t.TestResultLoggerExtension - 
    Test Successful for test givenTrueIsTrue_whenTestAbortedThenCaptureResult()
...
Test result summary for TestWatcherAPIUnitTest {ABORTED=1, SUCCESSFUL=1, DISABLED=2}

당연히 모든 테스트 방법이 완료되면 요약이 인쇄되는 것을 볼 수 있습니다.

6. 잡다한 것들

이 마지막 섹션에서는 TestWatcher 인터페이스로 작업할 때 알아야 할 몇 가지 미묘함을 검토해 보겠습니다 .

  • TestWatcher 확장은 테스트 실행에 영향을 줄 수 없습니다. 이것은 TestWatcher 에서 예외가 발생 하면 실행 중인 테스트까지 전파되지 않음을 의미합니다.
  • 현재 이 API는 @Test 메서드 및 @TestTemplate 메서드 의 결과를 보고하는 데만 사용됩니다.
  • 기본적으로 testDisabled 메소드에 이유가 제공되지 않으면 테스트 메소드의 정규화된 이름 뒤에 ' is @Disabled '가 포함됩니다.

7. 결론

요약하자면 이 예제에서는 JUnit 5 TestWatcher API를 사용하여 테스트 메소드 실행 결과를 처리하는 방법을 보여 주었습니다 .

예제의 전체 소스 코드는 GitHub 에서 찾을 수 있습니다 .

Junit footer banner