이번 포스팅에선 조건에 따라 반복 테스트를 할 수 있게 해주는 어노테이션에 대해 알아보겠습니다.
@RepeatedTest, @ParameterizedTest 처럼 어노테이션명이 Test로 끝나면 별도로 @Test 어노테이션이 없어도 테스트가 가능합니다.
@RepeatedTest
파라미터명 | 타입 | 설명 |
value | int | 반복 횟수 (반드시 0보다 커야함) (필수) |
name | String | 반복할 때 나타나는 테스트명 기본값 : "repetition " + 현재 반복 횟수 + " of " + 총 반복 횟수 |
@ReapeatedTest를 사용하면 RepetitionInfo 타입의 인자를 받을 수 있습니다. 앞에서 설명했어야 했는데 추가로 말하자면 JUnit 테스트는 기본적으로 TestInfo 타입의 인자도 받을 수 있습니다.
TestInfo
메소드명 | 타입 | 설명 |
getDisplayName() | String | @DisplayName 값이랑 동일 |
getTags() | Set<String> | @Tag 배열 값 |
getTestClass() | Optional<Class<?>> | 패키지 + 테스트 클래스명 |
getTestMethod() | Optional<Method> | 패키지명 + 테스트 클래스명 + 테스트 메소드 |
RepetitionInfo
메소드명 / 변수명 | 타입 | 설명 |
getCurrentRepetition() | int | 현재 반복 횟수 |
getTotalRepetitions() | int | 총 반복 횟수 |
DISPLAY_NAME_PLACEHOLDER | String | @DisplayName 값 |
SHORT_DISPLAY_NAME | String | 반복할 때 나타나는 테스트명 기본값 : "repetition " + 현재 반복 횟수 + " of " + 총 반복 횟수 |
LONG_DISPLAY_NAME | String | DISPLAY_NAME_PLACEHOLDER + " :: " + SHORT_DISPLAY_NAME |
TOTAL_REPETITIONS_PLACEHOLDER | String | 현재 반복 횟수 |
CURRENT_REPETITION_PLACEHOLDER | String | 총 반복 횟수 |
RepetitionInfo는 반드시 @RepeatedTest가 있어야합니다. 만약! 없으면 아래와 같은 에러가 납니다.
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [org.junit.jupiter.api.RepetitionInfo repetitionInfo] in method [void com.effortguy.junit5.RepeatedTestAnnotation.testRepetitionInfo(org.junit.jupiter.api.RepetitionInfo)].
예시
package com.effortguy.junit5;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
class RepeatedTestAnnotation {
// 5번 반복
@RepeatedTest(5)
void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
assertEquals(5, repetitionInfo.getTotalRepetitions());
}
//{displayName} = @DisplayName (없으면 기본값)
//{currentRepetition} = 현재 반복 횟수
//{totalRepetitions} = 총 반복 횟수
@RepeatedTest(value = 1, name = "{displayName} {currentRepetition}/{totalRepetitions}")
@DisplayName("Repeat!")
void customDisplayName(TestInfo testInfo) {
assertEquals("Repeat! 1/1", testInfo.getDisplayName());
}
//RepeatedTest.LONG_DISPLAY_NAME = DISPLAY_NAME_PLACEHOLDER + " :: " + SHORT_DISPLAY_NAME
@RepeatedTest(value = 1, name = RepeatedTest.LONG_DISPLAY_NAME)
@DisplayName("Details...")
void customDisplayNameWithLongPattern(TestInfo testInfo) {
assertEquals("Details... :: repetition 1 of 1", testInfo.getDisplayName());
}
}
결과
@ParameterizedTest
파라미터를 넣어서 테스트를 반복적으로 실행할 수 있게 해주는 어노테이션
파라미터명 | 타입 | 설명 |
name | String | @DisplayName 설정 |
DISPLAY_NAME_PLACEHOLDER | String | @DisplayName과 동일 |
INDEX_PLACEHOLDER | String | 현재 실행 인덱스 |
ARGUMENTS_PLACEHOLDER | String | 현재 실행된 파라미터 값 |
ARGUMENTS_WITH_NAMES_PLACEHOLDER | String | 현재 실행된 파라미터명 + "=" + 값 |
DEFAULT_DISPLAY_NAME | String | 기본값 "[" + INDEX_PLACEHOLDER + "] " + ARGUMENTS_WITH_NAMES_PLACEHOLDER |
@ParameterizedTest는 단독으로 사용되진 않고 어떤 파라미터를 사용하는지에 관한 어노테이션을 추가로 선언해줘야합니다.
추가로 선언하지 않았을 경우 아래와 같은 에러가 발생합니다.
org.junit.platform.commons.PreconditionViolationException: Configuration error: You must configure at least one set of arguments for this @ParameterizedTest
파라미터 어노테이션은 총 9개가 있는데 이번 포스팅에선 4개만 정리하고 다음 포스팅에서 나머지를 정리하겠습니다.
@ValueSource
다양한 타입의 파라미터를 배열로 받아서 사용할 수 있게 해주는 어노테이션
지원 타입 : short[], byte[], int[], long[], float[], double[], char[], boolean[], String[], Class<?>[]
각 타입명의 소문자에 + "s" 를 붙혀주면 파라미터명입니다. (Strings X, strings O)
파라미터 인자는 1개입니다. 2개 이상 넣을 시 에러가 발생합니다.
예시
package com.effortguy.junit5;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ParameterizedTestAnnotation {
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testWithValueSource(int intArg) {
assertTrue(intArg > 0 && intArg < 4);
}
// @ValueSource 파라미터로 여러개 값을 넣을 수 없음
// @ParameterizedTest
// @ValueSource(ints = { 1, 2, 3 }, strings = {"a", "b", "c"})
// void testWithValueSource(int intArg, string stringArg) {
// }
}
결과
@NullSource
메소드 인자에 null 값을 넣어줍니다. 메소드 인자가 1개일 때만 사용할 수 있습니다.
primitive type (int, long 등)에는 사용할 수 없습니다. 사용하면 아래와 같은 에러 발생합니다.
org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: Cannot convert null to primitive value of type int
package com.effortguy.junit5;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ParameterizedTestAnnotation {
@ParameterizedTest
@NullSource
void testWithNullSource(Integer integerArg) {
assertTrue(integerArg == null);
}
// primitive type에는 @NullSource 사용 불가
// @ParameterizedTest
// @NullSource
// void testWithNullSource(int intArg) {
// }
}
결과
@EmptySource
메소드 인자에 빈 값 객체 값을 넣어줍니다. 메소드 인자가 1개일 때만 사용할 수 있습니다.
지원 타입 : java.lang.String, java.util.List, java.util.Set, java.util.Map, primitive arrays (e.g., int[], char[][], etc.), object arrays (e.g.,String[], Integer[][], etc.).
package com.effortguy.junit5;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ParameterizedTestAnnotation {
@ParameterizedTest
void testWithEmptySource(Map map) {
assertTrue(map.isEmpty());
}
}
결과
@NullAndEmptySource
@NullSource와 @EmptySource를 합쳐놓은 어노테이션
package com.effortguy.junit5;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ParameterizedTestAnnotation {
@ParameterizedTest
@NullSource
@EmptySource
@ValueSource(strings = { " ", " ", "\t", "\n" })
void nullEmptyAndBlankStrings(String text) {
assertTrue(text == null || text.trim().isEmpty());
}
}
결과
다음 포스팅에선 @ParameterizedTest 의 나머지 5개 부가적인 어노테이션에 대해 포스팅하겠습니다.
읽어주셔서 감사합니다.
참고
https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-name-generator
댓글