JUnit5 동적 테스트 - @TestFactory

테스트 케이스를 동적으로 생성하는 방법에 대한 설명

동적 테스트

@TestFactory 어노테이션을 사용하여 테스트 케이스를 동적으로 생성할 수 있다.

package com.devkuma.junit5.dynamic;

import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.List;

import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;

public class DynamicTestFactoryTest {
    @TestFactory
    List<DynamicNode> testFactory() {
        return List.of(
                dynamicTest("Test1", () -> System.out.println("Dynamic Test1!!")),
                dynamicTest("Test2", () -> System.out.println("Dynamic Test2!!"))
        );
    }
}

실행 결과:

Dynamic Test1!!
Dynamic Test2!!
  • @TestFactory에서 어노테이션이 지정 메서드는 DynamicNode 컬렉션을 반환되야 한다.
    • 컬렉션은 엄밀히 말하면 다음 중 하나이다.
      • java.util.Collection
      • java.lang.Iterable
      • java.util.Iterator
      • java.util.stream.Stream
      • Array(배열)
    • Stream으로 반환하는 경우는 Jupiter에어 close()에서 해 주기 때문에, Files.lines()에서 생성하여 Stream 사용하여도 안전하다.
  • DynamicNode 자체는 추상 클래스이므로 실제로는 서브 클래스 DynamicTest 또는 DynamicContainer 중 하나를 사용하다.
    • 위의 예에서는 dynamicTest(String, Executable)라는 팩토리 메서드를 사용하여 DynamicTest 인스턴스를 생성한다.
      • 첫 번째 인수는 테스트 이름이다.
      • 두 번째 인수는 테스트 내용이다.

동적 테스트 라이프 사이클

@BeforeEach@AfterEach@TestFactory 설정된 메서드 전후에 실행되며, 각 동적 테스트 전후에는 실행되지 않는다.

package com.devkuma.junit5.dynamic;

import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.List;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;

public class DynamicLifeCycleTest {

    @BeforeEach
    void beforeEach() {
        System.out.println("beforeEach()");
    }

    @TestFactory
    List<DynamicNode> testFactory() {
        System.out.println("  testFactory()");
        return List.of(
                dynamicTest("Hoge", () -> System.out.println("    Dynamic Hoge!!")),
                dynamicTest("Fuga", () -> System.out.println("    Dynamic Fuga!!"))
        );
    }

    @Test
    void test() {
        System.out.println("  test()");
    }

    @AfterEach
    void afterEach() {
        System.out.println("afterEach()");
    }
}

실행 결과:

beforeEach()
  testFactory()
    Dynamic Test1!!
    Dynamic Test2!!
afterEach()
beforeEach()
  test()
afterEach()
  • testFactory()가 실행되기 전후에 beforeEach()afterEach()가 각각 한번씩 실행된 것을 볼 수 있다.

동적 테스트를 중첩 구조로 만들기

DynamicContainer를 사용하면 동적 테스트를 중첩 구조로 만들 수 있다.

package com.devkuma.junit5.dynamic;

import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.List;

import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;

public class DynamicContainerTest {

    @TestFactory
    List<DynamicNode> testFactory() {
        return List.of(
                dynamicContainer("Dynamic Container 1", List.of(
                        dynamicTest("Test 1-1", () -> System.out.println("Dynamic Test 1-1.")),
                        dynamicContainer("Dynamic Container 1-1", List.of(
                                dynamicTest("Test 1-1-1", () -> System.out.println("Dynamic Test 1-1-1.")),
                                dynamicTest("Test 1-1-2", () -> System.out.println("Dynamic Test 1-1-2."))
                        ))
                )),
                dynamicContainer("Dynamic Container 2", List.of(
                        dynamicTest("Test 2-1", () -> System.out.println("Dynamic Test 2-1.")),
                        dynamicTest("Test 2-2", () -> System.out.println("Dynamic Test 2-2."))
                ))
        );
    }
}
Dynamic Test 1-1.
Dynamic Test 1-1-1.
Dynamic Test 1-1-2.
Dynamic Test 2-1.
Dynamic Test 2-2.


최종 수정 : 2022-12-13