-
테스트 반복하기2 @ParameterizedTest이용한 추가 방법테스트/Junit5 2021. 2. 2. 18:08
2021/02/02 - [테스트/Junit5] - 테스트 반복하기 << 저번 시간에는 @Parameterized를 사용해 @ValueSource로 인자값을
String을 활용해 반복했다. 하지만 String객체말고 다른 primitive type 배열값도 할당 가능하다.
이번시간에는 Parameterrized애노테이션 ValueSource에 다른 primitype과 사용자가 만든 클래스로 테스트 반복하기를 배워보고자 한다.
사용하고자 하는 인자 값들을 할당하는 소스 애노테이션은 다음과 같다.
-
@ValueSource
-
@NullSource, @EmptySource, @NullAndEmptySource
-
@CvsSource
-
@ArgumentSource
자세한 내용은 공식레퍼런스 참조-> junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
또한, 사용자가 커스텀화한 클래스 그리고 여러개의 인자값이 존재한다면, 하나로 조합해 하나의 매개변수로 받을 수 있는 방법이 있다.
-> @ConverWith를 활용한 SimpleArgumentConverter 이용 -> 커스텀 클래스 생성후 사용한 경우
-> @AggregatwWtih를 활용한 ArgumentsAggregator 인터페이스 구현 -> 인자값 조합을 활욘한 경우.
아래 소스코드를 보면서 각 애노테이션이 어떻게 쓰이는지 이해해보자.
예제코드1. ValueSource에 여러값들 할당하기
@ValueSource의 경우 맨위에 이전에 실습한 소스코드에 더해 추가적으로 설명한다.
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(ints = {1,2,3}) void ParameterizedTest(Integer limt){ System.out.println(limt); }
int형 배열을 인자값으로 할당한 후 반복되는 메서드의 매개변수로 Integer warpper클래가 왔다. -> primitive으로 매개변수를 사용하면 안된다.
또한 String의 문자열인 경우 암묵적인 형변환이 일어난다. - String -> Boolean
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(strings = {"true"}) void ParameterizedTest(Boolean test){ System.out.println(test instanceof Boolean); }
예제코드2. 커스텀한 클레스를 만들고 반복테스트하기.
public class Study { private int limit; public Study(int limlit) { if(limlit < 0){ throw new IllegalArgumentException("음수는 올 수 없어요."); } this.limit = limlit; } public int getlimit() { return this.limit; } }
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(ints = {1,2,3}) void ParameterizedTest(Study study){ System.out.println(study.getlimit()); }
Integer 클래스가 아닌 Study클래스로 형변환을 하고 싶은 경우 다음과 같이 구현해준다.
1. SimpleArgumentConverter를 상속받는 구현체를 구현하고 제공해야한다.
2. @ConvertWith애노테이션을 메서드의 명시적 변환 매개변수에 사용한다.
static class StudyConverter extends SimpleArgumentConverter { @Override protected Object convert(Object o, Class<?> aClass) throws ArgumentConversionException { assertEquals(Study.class, aClass, ()->"can only convert to study"); return new Study(Integer.parseInt(o.toString())); } }
convert메서드의 Object o, Class<?> aClass가 전달되는 것을 볼 수 있는데, o의 경우엔 변환할 값(즉 1,2,3등), aClass의 경우엔 변환하고자 하는 클레스 타입이온다. 이렇게 SimpleArgumentConverter 추상 클레스를 구현한 후
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name = "{index} {displayName} message={0} ") @ValueSource(ints = {1, 2, 3}) void ParameterizedTest(@ConvertWith(StudyConverter.class) Study study) { System.out.println(study.getlimit()); }
@ConverWith애노테이션을 사용해 명시적 형변환을 일으킨다.
결과는 다음과 같다.
예제코드3. 2개의 매개변수로 반복하는 테스트
@CsvSource로 반복할 매개변수를 2개 설정한다.
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name = "{index} {displayName} message={0} ") @CsvSource({"10, 자바 test","20, 스프링"}) void ParameterizedTest(Integer integer,String string) { Study study = new Study(integer,string); System.out.println(study); }
Study생성자는 다음과 같다.
package com.example.junittest; public class Study { private int limit; private Studystatus status = Studystatus.DRAFT; private String name; public Study(int limlit, String name) { if (limlit < 0) { throw new IllegalArgumentException("음수는 올 수 없어요."); } this.name = name; this.limit = limlit; } public Studystatus getStatus() { return this.status; } public int getlimit() { return this.limit; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setLimit(int limit) { this.limit = limit; } @Override public String toString() { return "Study{" + "limit=" + limit + ", status=" + status + ", name='" + name + '\'' + '}'; } }
테스트에 반복할 매개변수가 {{"10", "자바 test"}, {"20","스프링"}}이 각각 테스트로 진행되며, 숫자들은 암묵적인 형 변환으로인해 Integer로 인자값이 변환된다.
예제코드4-1. ArgumetsAccesor을 통한 매개변수가 2개인 인자값을 통해 반복테스트하기.
- ArgumentsAccessor을 통해 여러개의 매개변수를 하나의 인자값으로 조합하기.
- ArgumentsAccesor.getInteger or .getString 매소드로 인자값 받기
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name = "{index} {displayName} message={0} ") @CsvSource({"10, 자바 test","20, 스프링"}) void ParameterizedTest(ArgumentsAccessor argumentsAccessor) { Study study =new Study(argumentsAccessor.getInteger(0),argumentsAccessor.getString(1)); System.out.println(study); }
예제코드4-2 Aggregator을 활용해 커스텀 Accesor을 구현하기
- ArgumentsAggregator 인터페이스를 구현해야한다.
- ArgumentsAggregator에 사용한 클레스를 테스트 매개변수(ParameterizedTest) @AggregateWith 애너테이션 매개변수에 지정해주어야한다.
- 인자값 타입을 지정해준다.-> Study커스텀 태그를 사용했으니 ParameterizedTest매개변수로 Study타입을 지정해야 한다.
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name = "{index} {displayName} message={0} ") @CsvSource({"10, 자바 test","20, 스프링"}) void ParameterizedTest(@AggregateWith(argumentAggregator.class) Study study) { System.out.println(study); } static class argumentAggregator implements ArgumentsAggregator{ @Override public Object aggregateArguments(ArgumentsAccessor argumentsAccessor, ParameterContext parameterContext) throws ArgumentsAggregationException { return new Study(argumentsAccessor.getInteger(0),argumentsAccessor.getString(1)); } }
예제코드. @NullSource, @EmptySource, @NullandEmptySource
@NullSource - Null을 인자값으로 할당한다.
@EmptySource - 비어있는 문자열을 할당한다.
@NullandEmptySource - 위의 두 가지 경우를 할당한다
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(strings = {"JUnit5","배우고","테스트 잘하자"}) @NullSource // @EmptySource // @NullAndEmptySource void ParameterizedTest(String message){ System.out.println(message); }
null값이 반복 테스트에 추가된 것을 알수있다.
이번에는 @EmptySource만 주석을 해제해보자
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(strings = {"JUnit5","배우고","테스트 잘하자"}) // @NullSource @EmptySource // @NullAndEmptySource void ParameterizedTest(String message){ System.out.println(message); }
빈 문자열이 할당되었다.
다음은 두가지 경우를 할당하는 @NullandEmptySource애노테이션을 사용해보자.
@DisplayName("반복 스터디 만들기2") @ParameterizedTest(name ="{index} {displayName} message={0} ") @ValueSource(strings = {"JUnit5","배우고","테스트 잘하자"}) // @NullSource // @EmptySource @NullAndEmptySource void ParameterizedTest(String message){ System.out.println(message); }
위의 두가지 경우(null, empty)가 테스트에 추가되었다.
-