어제 오늘 내일

[JUnit5] dynamicTest()로 동적 테스트 정의하기 본문

IT/JUnit

[JUnit5] dynamicTest()로 동적 테스트 정의하기

hi.anna 2026. 1. 23. 01:04

1. dynamicTest()란 무엇인가

dynamicTest()는 JUnit5의 동적 테스트(Dynamic Test) 기능을 생성하는 팩토리 메서드로, 실행 시점에 테스트를 구성할 수 있게 한다.
정적 테스트(@Test)와 달리, 테스트 개수와 구성 요소가 코드 실행 중 동적으로 결정된다는 점이 가장 큰 특징이다.

데이터 기반 테스트, 반복 패턴 테스트, 입력값 목록을 기반으로 한 자동 생성 테스트 등에 매우 적합하다.

 

2. 기본 사용 예제

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

import java.util.List;

class DynamicTestBasicExample {

    @TestFactory
    List<DynamicTest> dynamicTests() {
        return List.of(
            DynamicTest.dynamicTest("1 + 1 = 2", () -> {
                assertEquals(2, 1 + 1);
            }),
            DynamicTest.dynamicTest("2 * 3 = 6", () -> {
                assertEquals(6, 2 * 3);
            })
        );
    }
}

설명

  • @TestFactory가 붙은 메서드는 정적 테스트가 아니라 “테스트 생성기”이다.
  • DynamicTest.dynamicTest()는 테스트 이름과 실행 코드를 받아 하나의 동적 테스트를 만든다.

 

3. 컬렉션 기반 동적 테스트 생성하기

입력값 목록을 기반으로 자동 테스트를 만들 때 유용하다.

@TestFactory
List<DynamicTest> dynamicTestsFromList() {
    List<Integer> numbers = List.of(1, 2, 3, 4);

    return numbers.stream()
        .map(n -> DynamicTest.dynamicTest(
            n + "는 양수인가?",
            () -> assertTrue(n > 0)
        ))
        .toList();
}

활용 포인트

  • 입력 데이터만 늘리면 테스트도 자동 확장됨
  • 데이터 기반 검증에 최적화

 

4. 매핑 기반(Key-Value) 동적 테스트 생성하기

예: 문자열 길이 규칙을 검증하는 테스트.

@TestFactory
List<DynamicTest> dynamicTestsFromMap() {
    Map<String, Integer> cases = Map.of(
        "hello", 5,
        "world", 5,
        "java", 4
    );

    return cases.entrySet().stream()
        .map(entry -> DynamicTest.dynamicTest(
            "'" + entry.getKey() + "' 길이 확인",
            () -> assertEquals(entry.getValue().intValue(), entry.getKey().length())
        ))
        .toList();
}

설명

  • Map의 엔트리별로 독립적인 테스트가 생성됨
  • 다양한 입력-결과 조합을 쉽게 표현 가능

 

5. 예외 검증을 위한 동적 테스트

동적 테스트에서도 예외 검증을 그대로 사용할 수 있다.

@TestFactory
List<DynamicTest> exceptionDynamicTests() {
    List<String> invalidInputs = List.of("", null);

    return invalidInputs.stream()
        .map(input -> DynamicTest.dynamicTest(
            "Invalid input: " + input,
            () -> assertThrows(IllegalArgumentException.class, () -> validate(input))
        ))
        .toList();
}

private void validate(String input) {
    if (input == null || input.isEmpty()) {
        throw new IllegalArgumentException();
    }
}

 

6. 동적 테스트 활용이 좋은 상황

  • 반복적 테스트를 데이터 기반으로 자동 생성하고 싶을 때
  • 입력값 목록이 다양해 정적 테스트로 관리하기 어려울 때
  • 동일한 검증 로직을 여러 케이스에 적용해야 할 때
  • 외부 데이터(JSON, CSV 등)를 기반으로 테스트 생성할 때
  • API 응답값 등을 기반으로 테스트를 동적으로 구성해야 할 때

동적 테스트는 정적 테스트가 처리하기 어려운 유연한 테스트 구성에 매우 강력하다.

7. 동적 테스트와 정적 테스트의 차이 요약

구분  정적 테스트(@Test) 동적 테스트(dynamicTest)
테스트 개수 컴파일 시 고정 실행 시 결정
구조 메서드 단위 데이터·스트림 기반 자유 구성
선언 방식 @Test 메서드 @TestFactory 기반 테스트 생성기
유용성 단순·명확한 테스트 반복·데이터 기반 테스트에 적합

 

 

반응형
Comments