이번 포스팅에선 이전 포스팅에서 다뤘던 @ParameterizedTest를 사용할 때 부가적으로 사용해야 하는 어노테이션 9개 중 나머지 3개를 다루겠습니다.
@EnumSource
Enum에 정의된 상수들을 테스트하기 위한 어노테이션
파라미터명 | 타입 | 설명 |
value | Class<? extends Enum<?>> | 테스트할 Enum 클래스 기본값 : NullEnum.class |
names | String[] | 검색 조건 (문자열, 정규식) mode에서 사용됌 |
mode | Mode | INCLUDE : names.contains(name) << Default EXCLUDE : !names.contains(name)) MATCH_ANY : patterns.stream().anyMatch(name::matches) (조건에 하나라도 부합되는 상수) MATCH_ALL : patterns.stream().allMatch(name::matches) (조건에 모두 부합되는 상수) name : Enum 명 names : names 필드 patterns : names에 있는 정규식 |
메소드 인자가 Enum이 아닐 경우 에러 발생
org.junit.platform.commons.PreconditionViolationException: First parameter must reference an Enum type (alternatively, use the annotation's 'value' attribute to specify the type explicitly): void com.effortguy.junit5.parameterizedTestAnnotation.EnumSourceAnnotation.testEnumSourceValue2(java.lang.String)
예시
value
value는 optional로 없을 경우 메소드 인자에 선언된 Enum 타입이 default 값으로 주입
package com.effortguy.junit5.parameterizedTestAnnotation;
import com.effortguy.junit5.enumsource.Day;
import com.effortguy.junit5.enumsource.Month;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import static org.junit.jupiter.params.provider.EnumSource.Mode.*;
import static org.junit.jupiter.params.provider.EnumSource.Mode.MATCH_ALL;
public class EnumSourceAnnotation {
@ParameterizedTest
@EnumSource(value = Month.class)
void testEnumSourceValue(Month month) {
}
//value 생략 시 메소드 인자 값 정보를 읽어서 주입
@ParameterizedTest
@EnumSource
void testEnumSourceValue2(Month month) {
}
}
mode = Mode.INCLUDE (Default)
enum name 값이 May 인 것만 테스트
@ParameterizedTest
@EnumSource(mode = INCLUDE, names = {"May"})
void testEnumSourceInclude(Month month) {
}
mode = Mode.EXCLUDE
enum name 값이 May, March 인 것 제외하고 테스트
@ParameterizedTest
@EnumSource(mode = EXCLUDE, names = {"May", "March"})
void testEnumSourceExclude(Month month) {
}
mode = Mode.MATCH_ANY
정규식 "^.*sday$" (sday로 끝나는), "^.*esday$" (esday로 끝나는) 조건 중 하나만 만족해도 테스트
@ParameterizedTest
@EnumSource(mode = MATCH_ANY, names = {"^.*sday$","^.*esday$"})
void testEnumSourceMatchAny(Day day) {
}
mode = Mode.MATCH_ALL
정규식 "^.*sday$" (sday로 끝나는), "^.*esday$" (esday로 끝나는) 조건 모두 만족할 경우 테스트
@ParameterizedTest
@EnumSource(mode = MATCH_ALL, names = {"^.*sday$","^.*esday$"})
void testEnumSourceMatchAll(Day day) {
}
@MethodSource
factory 메소드가 리턴해주는 값을 가지고 반복 테스트하는 어노테이션
factory 메소드 조건
1. 반드시 static, 테스트 클래스에 @TestInstance(Lifecycle.PER_CLASS)가 있을 경우엔 필요없음
2. 인자가 없어야함
3. Stream 타입으로 리턴해야함
파라미터명 | 타입명 | 설명 |
value | String | factory 메소드 명 기본값 : 테스트 메소드명이랑 동일 |
예시
테스트 메소드의 인자가 1개인 경우
package com.effortguy.junit5.parameterizedTestAnnotation;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class MethodSourceAnnotation {
// @MethodSource에 value 명시 안 하면 테스트 메소드와 동일한 것 찾음
@ParameterizedTest
@MethodSource
void testWithDefaultLocalMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> testWithDefaultLocalMethodSource() {
return Stream.of("apple", "banana");
}
}
테스트 메소드의 인자가 2개 이상인 경우 arguments를 사용해서 리턴해줘야합니다.
@ParameterizedTest
@MethodSource("stringIntAndListProvider")
void testWithMultiArgMethodSource(String str, int num, List<String> list) {
assertEquals(5, str.length());
assertTrue(num >=1 && num <=2);
assertEquals(2, list.size());
}
static Stream<Arguments> stringIntAndListProvider() {
return Stream.of(
arguments("apple", 1, Arrays.asList("a", "b")),
arguments("lemon", 2, Arrays.asList("x", "y"))
);
}
@CvsSource
CSV (Comma Seperated Value) 형식의 데이터로 반복 테스트를 합니다.
파라미터명 | 타입 | 설명 |
value | String[] | CVS 형식의 데이터 |
delimiter | char | delimiter를 변경 (char 형) delimiterString 하고 같이 사용 불가 |
delimiterString | String | delimiter를 변경 (String 형) delimiter 와 같이 사용 불가 delimiter, delimiterString 굳이 2개를 둔 이유는 char 형으로 굳이 사용해야 하는 경우가 있어서 그런 거 같습니다. |
emptyValue | String | CVS 데이터 중 빈 값인 경우 대체되는 값 |
nullValues | String[] | CVS 데이터 중 null 값으로 대체할 값 |
문자열은 " " (double quote), 문자열 안에 항목 구분하기 위해선 ' ' (single quote) 사용
'' 로 빈 값을 표현하면 "" 과 동일, '' 도 사용하지 않으면 null로 처리
예제 | 리턴 값 |
@CsvSource({ "apple, banana" }) | "apple", "banana" |
@CsvSource({ "apple, 'lemon, lime'" }) | "apple", "lemon, lime" |
@CsvSource({ "apple, ''" }) | "apple", "" |
@CsvSource({ "apple, " }) | "apple", null |
@CsvSource(value = { "apple, banana, NIL" }, nullValues = "NIL") | "apple", "banana", null |
예시
value
package com.effortguy.junit5.parameterizedTestAnnotation;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.*;
public class CsvSourceAnnotation {
@ParameterizedTest
@CsvSource(value = {
"apple, 1",
"banana, 2",
"'lemon, lime', 0xF1"
})
void testWithCsvSourceValue(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
}
delimiter, delimiterString
delimiter, delimiterString 결과는 동일
@ParameterizedTest
@CsvSource(value = {
"apple: 1"
}, delimiter = ':')
void testWithCsvSourceDelimiter(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
@ParameterizedTest
@CsvSource(value = {
"apple: 1"
}, delimiterString = ":")
void testWithCsvSourceDelimiterString(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
emptyValue
빈 값을 1로 바꾸는 테스트
@ParameterizedTest
@CsvSource(value = {
"apple, ''"
}, emptyValue = "1")
void testWithCsvSourceEmptyValue(String fruit, int rank) {
assertNotNull(fruit);
assertNotEquals(0, rank);
}
nullValues
apple, NL 을 null 값으로 바꾸는 테스트
@ParameterizedTest
@CsvSource(value = {
"apple, NL"
}, nullValues = {"NL", "apple"})
void testWithCsvSourceNullValues(String fruit, Integer rank) {
assertNull(fruit);
assertNull(rank);
}
이번 포스팅에서 반복테스트 정리를 끝내려고 했는데 너무 길어져서 다음 포스팅에 나머지 2개 어노테이션을 정리하겠습니다.
읽어주셔서 감사합니다.
참고
https://junit.org/junit5/docs/current/user-guide/#writing-tests-display-name-generator
댓글