반응형
테스트 반복하기
- 테스트를 매번 실행할 때마다 랜덤 값을 사용하거나, 테스트 실행 타이밍에 따라 달라질 수 있는 조건이 있는 경우에 테스트를 여러 번 반복적으로 실행하여 검증할 수 있다.
@RepeatedTest
- 테스트 반복 횟수와 반복되는 테스트 이름을 설정할 수 있다.
- {displayName} :
@DisplayName
으로 지정된 값(@RepeatedTest
메서드의 표시 이름)
- {currentRepetition} : 현재 반복 횟수
- {totalRepetitions} : 총 반복 횟수
- {displayName} :
- RepetitionInfo 타입의 인자를 받을 수 있다.
@ParameterizedTest
- junit-jupiter-params 의존성을 추가해주어야 한다.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
- 테스트에 여러 다른 매개변수를 대입해가며 반복 실행한다.
- {displayName} :
@DisplayName
으로 지정된 값
- {index} : 현재 호출 인덱스(1-based)
- {arguments} : 쉼표로 구분된 완전한 인수 목록
- {0}, {1}, ... : arguments 인덱스 번호
- 예) @CsvSource({"10, '자바 스터디'", "20, 스프링"})
- {0} : 10, 20 출력
- {1} : 자바 스터디, 스프링 출력
- {displayName} :
- 인자 값들의 소스(Sources of Arguments)
- @ValueSource
- 리터럴 값의 단일 배열을 지정할 수 있으며 매개 변수화된 테스트 호출 시, 단일 인수를 제공하는 데만 사용할 수 있다.
- @NullSource
- null 주석이 달린 @ParameterizedTest 메서드에 단일 인수를 제공합니다 .
- @EmptySource
- 비어있는 문자열을 추가
- 지원타입 목록
- String
- List
- Set
- Map
- primitive arrays(int[], char[][], etc)
- object arrays(String[], Integer[][], etc)
- 지원되는 타입의 하위 타입은 지원하지 않는다.
- 예) int[]는 지원하지만 int는 지원하지 않는다.
- @NullAndEmptySource
@NullSource
+@EmptySource
- @EnumSource
- Enum상수를 사용하는 편리한 방법을 제공한다.
- @MethodSource
- 테스트 클래스 또는 외부 클래스의 하나 이상의 팩토리 메소드를 참조할 수 있다 .
- @CsvSource
- 인수 목록을 쉼표로 구분된 값(즉, String리터럴) 으로 표현할 수 있다 .
- 여러 인자를 전달
- @CsvFileSource
- 클래스 경로 또는 로컬 파일 시스템에서 CSV 파일을 사용할 수 있다.
- CSV 파일의 각 행은 매개변수화된 테스트를 한 번 호출한다.
- @ArgumentsSource
- 재사용 가능한 사용자 지정 ArgumentsProvider를 지정하는 데 사용할 수 있다.
- @ValueSource
- 인자 값 타입 변환(Argument Conversion)
- 암묵적인 타입 변환(Implicit Conversion)
- 선언된 소스에서 제공한 실제 유형이 String인 경우 문자열은 자동으로 변환된다.
- 문자열에서 위의 표에 나열된 대상 유형으로의 암시적 변환 외에도 JUnit Jupiter는 String대상 유형이 정의된 대로 정확히 하나의 적합한 팩토리 메소드 또는 팩토리 생성자 를 선언하는 경우 지정된 대상 유형으로의 자동 변환을 위한 폴백 메커니즘을 제공한다.
- 팩토리 메소드 : 단일
String
인수를 허용하고 대상 유형의 인스턴스를 반환하는 비공개가 아닌static
메소드. 메소드 이름은 임의적일 수 있으며 특정 규칙을 따를 필요는 없다.
- 팩토리 생성자 : 단일
String
인수를 허용하는 대상 유형의 비공개가 아닌 생성자 . 대상 유형은 최상위 클래스(public Class) 또는static
중첩 클래스 로 선언되어야 한다.
- 만약, 여러 팩토리 메소드가 발견되면 무시된다.
- 팩토리 메소드와 팩토리 생성자 둘 다 발견되면 생성자 대신 팩토리 메소드가 사용된다.
- 팩토리 메소드 : 단일
- 명시적인 타입 변환(Explicit Conversion)
- SimpleArgumentConverter를 상속 받은 구현체를 제공 해야한다.
- 구현체는 public Class 또는 static Inner Class로 선언되어야 한다.
- 해당 구현체를 이용하여 커스텀한 타입으로 변환할 수 있다.
- 예) 숫자 → Study 타입으로
- @ConvertWith
- 특정 매개변수에 사용할 ArgumentConverter를 명시적으로 지정할 수 있다.
- 예) @ConvertWith(StudyConverter.class)
- SimpleArgumentConverter를 상속 받은 구현체를 제공 해야한다.
- 암묵적인 타입 변환(Implicit Conversion)
- 인자 값 집합(Argument Aggregation)
- ArgumentsAccessor
- 여러 인자 값을 ArgumentsAccessor를 통해서 사용할 수 있다.
- 암시적 변환에서의 형식 변환이 지원된다.
- 커스텀 Accessor 사용
- ArgumentsAggregator 인터페이스 구현한다.
- 반드시
public Class
또는static Inner Class로
선언되어야 한다.
- 반드시
- @AggregateWith
- 커스텀 Accessor 사용 시, 어떤 Aggregator를 쓰겠다고 명시적으로 지정할 수 있다.
- 예) @AggregateWith(StudyAggregator.class) Study study)
- ArgumentsAggregator 인터페이스 구현한다.
- ArgumentsAccessor
JUnit 5 - 테스트 반복하기 예제
Study
public class Study { private StudyStatus status = StudyStatus.DRAFT; private int limit; private String name; public Study(int limit, String name) { this.limit = limit; this.name = name; } public Study(int limit) { if (limit < 0) { throw new IllegalArgumentException("limit은 0보다 커야 한다."); } this.limit = limit; } public Study() { } public StudyStatus getStatus() { return this.status; } public int getLimit() { return limit; } public String getName() { return name; } @Override public String toString() { return "Study{" + "status=" + status + ", limit=" + limit + ", name='" + name + '\'' + '}'; } }
RepeatFastTest
import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Tag; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") @RepeatedTest(value = 10, name = "{displayName} 반복, {currentRepetition}/{totalRepetitions}") public @interface RepeatFastTest { }
StudyTest
@RepeatFastTest void repeatTest(RepetitionInfo repetitionInfo){ System.out.println("test" + repetitionInfo.getCurrentRepetition() + "/" + repetitionInfo.getTotalRepetitions()); } @ParameterizedTest(name = "{index}. {displayName}, message={0}") @ValueSource(strings = {"날씨가", "많이", "더워지고", "있네요."}) @NullAndEmptySource void parameterizedTest(String message){ System.out.println(message); } @ParameterizedTest(name = "{index}. {displayName}, message={0}") @ValueSource(ints = {10, 20, 30}) @NullSource void parameterizedTest2(Integer limit){ System.out.println(limit); } /* * ValueSource를 Study 타입으로 받을 수도 있다.(인자 1개) */ @ParameterizedTest(name = "{index}. {displayName}, message={0}") @ValueSource(ints = {10, 20, 30}) void parameterizedTest3(@ConvertWith(StudyConverter.class) Study study){ System.out.println(study.getLimit()); } //SimpleArgumentConverter 상속 받은 구현체를 이용하여 파라미터를 특정 타입으로 변환 가능 //SimpleArgumentConverter는 하나의 인자에만 적용할 수 있다. static class StudyConverter extends SimpleArgumentConverter{ @Override protected Object convert(Object source, Class<?> targetType) throws ArgumentConversionException { assertEquals(Study.class, targetType, "Can only convert to Study"); return new Study((Integer.parseInt(source.toString()))); } } /* * CsvSource를 Study 타입으로 받을 수도 있다.(인자 2개) */ //1. 두 개의 인자를 받아서 Study 생성 @ParameterizedTest(name = "{index}. {displayName}, message={0}, {1}") @CsvSource({"10, '자바 스터디'", "20, 스프링"}) void parameterizedTest4(Integer limit, String name){ Study study = new Study(limit, name); System.out.println(study); } //2. ArgumentsAccessor를 이용해서 Study 생성 @Tag("fast") @ParameterizedTest(name = "{index}. {displayName}, message={0}, {1}") @CsvSource({"30, 'HTTP'", "40, 스프링 부트"}) void parameterizedTest5(ArgumentsAccessor argumentsAccessor){ Study study = new Study(argumentsAccessor.getInteger(0), argumentsAccessor.getString(1)); System.out.println(study); } //3. 커스텀 Accessor를 이용해서 Study 생성 @ParameterizedTest(name = "{index}. {displayName}, message={0}, {1}") @CsvSource({"40, 'JPA'", "50, JUnit"}) void parameterizedTest6(@AggregateWith(StudyAggregator.class) Study study){ System.out.println(study); } //커스텀 Accessor static class StudyAggregator implements ArgumentsAggregator { @Override public Object aggregateArguments(ArgumentsAccessor argumentsAccessor, ParameterContext parameterContext) throws ArgumentsAggregationException { return new Study(argumentsAccessor.getInteger(0), argumentsAccessor.getString(1)); } }
[참고자료]
반응형
'Java > Test Framework' 카테고리의 다른 글
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 테스트 설정 파일 (0) | 2021.07.26 |
---|---|
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 테스트 인스턴스 전략 변경 및 테스트 순서 설정 (0) | 2021.07.26 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 태깅과 필터링 (0) | 2021.07.23 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - 조건에 따라 테스트 실행 (0) | 2021.07.21 |
[더 자바, 애플리케이션을 테스트하는 다양한 방법] JUnit 5 - Assertion (0) | 2021.07.19 |