[Junit] @ParameterizedTest 객체에 값을 자동으로 넣어주는 Auto Param - @autosource
지인이 테스트 코드를 짤 떄, 파라미터의 값을 자동으로 세팅해주는 요상한게 생겼다고 해서 사용을 해보았습니다.
강남언니 CTO 이규원님이 만든 오픈소스라고 하더군요
AutoParams는 AutoFixture에서 영감을 받은 Java의 매개변수화된 테스트를 위한 임의 테스트 데이터 생성기입니다.
Auto Param 이 제공하는 기능은,
- 매개변수에 값을 자동으로 주입해줍니다.
- 리터럴 변수, Enum, Object, Generic, Collection, Primitive Type Stream 까지 지원을 해줍니다.. (굉장해)
@AutoSource 사용해보기
@ParameterizedTest 와 @AutoSource 어노테이션을 사용이용해서 간편하게 사용할 수 있습니다.
Auto Param을 사용하기 위해서는 자바 8버전 이상을 사용하셔야합니다.
1) Install
Maven
<dependency>
<groupId>io.github.autoparams</groupId>
<artifactId>autoparams</artifactId>
<version>1.1.1</version>
</dependency>
Gradle
testImplementation 'io.github.autoparams:autoparams:1.1.1'
2) 사용방법
- 사용방법이 진짜 별거 없습니다. 아래는 @AutoSource 를 사용하지 않을 때 List 안에 일일이 객체값을 넣어주고 있습니다.
- Test 코드임에도 불구하고, 이런게 쌓이다 보면 굉장히 귀찮고, 코드가 보기 힘들어질 때 가 있습니다.
- @MethodSource 나 @ValueSource 를 사용하더라도 데이터를 세팅해주어야하는 것은 마찬가지입니다.
기존 Test 코드
- 일일히 데이터를 세팅해주어야 함
@Test
@DisplayName("auto param test - 미사용")
void dtoByScoreSorted() {
List<Dto> dtoList = List.of(
new Dto(1, 1,1,1,1,1.0),
new Dto(1, 1,1,1,1,2.0),
new Dto(1, 1,1,1,1,5.0),
new Dto(1, 1,1,1,1,19.0),
new Dto(1, 1,1,1,1,13.0),
new Dto(1, 1,1,1,1,22.0),
new Dto(1, 1,1,1,1,4.0),
new Dto(1, 1,1,1,1,51.0),
new Dto(1, 1,1,1,1,3.0),
new Dto(1, 1,1,1,1,191.0)
);
DtoGroup group = new DtoGroup(Dto);
Assertions.assertThat(group.getSorted())
.isSortedAccordingTo((o1, o2) -> o1.getScore() < o2.getScore() ? 1 : 0);
}
Auto Param Test 코드
- @AutoSource 를 사용하여 데이터 세팅하는 코드가 사라지니, 조금 더 명확한 코드가 된 것만 같은 기분입니다(?)
- Collection Type (List)를 매개변수로 주니, List 요소의 복합 Object 안에 값이 mocking 된게 아니라, 실제 값을 가지고 있었습니다.
@ParameterizedTest
@AutoSource
@Repeat(10)
@DisplayName("auto param test - 사용")
void rankInfoGroupByScoreSorted(List<Dto> dtoList) {
DtoGroup group = new DtoGroup(dtoList);
assertThat(group.getDtoList())
.isSortedAccordingTo((o1, o2) -> o1.getScore() < o2.getScore() ? 1 : 0);
}
(아 @AutoSource 를 사용했을 떄, List 의 사이즈는 3으로 고정되던데,, 이거 사이즈를 더 늘리는 방법 아시는 분..? 흠..)
아무튼 굉장히 편리합니다!!
3) Auto Param 데이터 주입 원리
저는 복합 객체를 가지는 List 에 데이터를 주입 받아서 사용했는데, 이 복합객체에 대한 데이터 주입은 "생성자"를 사용하여 데이터를 주입한다고 합니다.
AutoParam 의 복합 유형 객체 생성 규칙
- @ConstructorProperties주석으로 장식된 생성자 가 우선적으로 선택됩니다.
- AutoParams는 매개변수가 가장 적은 생성자를 선택합니다.
✨ 운영코드에 @ConsturctorProerties 어노테이션을 삽입할 수 없으니 Test Fixture 와 함께 사용한다면, 굉장히 강력하게 사용할 수 있을거 같다는 생각이 들었습니다..!
4) 다양한 @AutoSource 사용 예시
사실 github 의 readme 내용을 거의 뱉긴거지만, 나중에 제가 볼 떄 귀찮을 거 같으니까 정리해두겠습니다.
타입별 AutoSource예시
1. Primitive Type - 여러 파라미터 사용하기
@ParameterizedTest
@AutoSource
void testMethod(boolean x1, int x2, long x3, float x4, double x5, char x6) {
}
2. Enum Types - Enum 값 중 랜덤으로 들어감
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
@ParameterizedTest
@AutoSource
void testMethod(Day day) {
}
3. Generic Type, Collections, Stream 까지 지원하는 모든 타입은 매개변수로 선언하면 자동으로 값이 주입됨
@ParameterizedTest
@AutoSource
void testMethod(Map<String, ComplexObject> map, HashMap<UUID, ComplexObject> hashMap) {
}
@ParameterizedTest
@AutoSource
void testMethod(Stream<ComplexObject> stream) {
}
@ParameterizedTest
@AutoSource
void testMethod(IntStream intStream, LongStream longStream, DoubleStream doubleStream) {
}
AutoSource가 제공하는 다양한 기능 예시
1. @Fix
- 해당 어노테이션을 타입에 적용하면, 이후 같은 타입인 변수에는, 고정된 값이 들어감
class ValueContainer {
private final String value;
public ValueContainer(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
@ParameterizedTest
@AutoSource
void testMethod(@Fix String arg1, String arg2, ValueContainer arg3) {
assertEquals(arg1, arg2);
assertEquals(arg1, arg3.getValue());
}
2. @ValueAutoSource
- @ValueSource + @AutoSource 의 결합
- 첫 번째 매개변수에는, @ValueSource 에서 설정한 값이 들어가고, 나머지는 @AutoSource 가 주입한다.
@ParameterizedTest
@ValueAutoSource(strings = {"foo"})
void testMethod(String arg1, String arg2) {
assertEquals("foo", arg1);
assertNotEquals(arg1, arg2);
}
@Fix 도 같이 사용할 수 있다고 합니다.
class ValueContainer {
private final String value;
public ValueContainer(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
@ParameterizedTest
@ValueAutoSource(strings = {"foo"})
void testMethod(@Fix String arg1, String arg2, ValueContainer arg3) {
assertEquals("foo", arg2);
assertEquals("foo", arg3.getValue());
}
3. @CsvAutoSource, @MethodAutoSource 모두 동일한 특징을 가집니다.
- @CsvAutoSource는 앞의 2개의 매개변수에 값을 주입하고
- @MethodAutoSource 도 마찬가지로 순서대로 매개변수에 값이 지정되고, 나머지 매개변수는 값이 주입됩니다.
// @CsvAutoSource
@ParameterizedTest
@CsvAutoSource({"16, foo"})
void testMethod(int arg1, String arg2, String arg3) {
assertEquals(16, arg1);
assertEquals("foo", arg2);
assertNotEquals(arg2, arg3);
}
// @MethodAutoSource
@ParameterizedTest
@MethodAutoSource("factoryMethod")
void testMethod(int arg1, String arg2, String arg3) {
assertEquals(16, arg1);
assertEquals("foo", arg2);
assertNotEquals(arg2, arg3);
}
static Stream<Arguments> factoryMethod() {
return Stream.of(
Arguments.arguments(16, "foo")
);
}
// @Fix + @MethodAutoSource
class ValueContainer {
private final String value;
public ValueContainer(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
@ParameterizedTest
@MethodAutoSource("factoryMethod")
void testMethod(int arg1, @Fix String arg2, ValueContainer arg3) {
assertEquals("foo", arg3.getValue());
}
static Stream<Arguments> factoryMethod() {
return Stream.of(
Arguments.arguments(16, "foo")
);
}
4. @Min, @Max - AutoSource 의 주입되는 값 범위 지정
- 아직 정수형 타입 (int, Integer) 만 지원되는 것 같습니다. (2022.12. 27)
@ParameterizedTest
@AutoSource
void testMethod(@Min(1) @Max(10) int value) {
assertTrue(value >= 1);
assertTrue(value <= 10);
}
5. 🔥 @Customization
- AutoSource로 주입되는 데이터의 규칙을 정할 수 있는 거 같군요!!!! (이거 굉장하다)
- Customizer 인터페이스를 구현하여 사용하면 되는 것 같습니다!
- 이걸 이용하면 List의 size 도 늘릴 수 있겠네요 (
하지만 귀찮으니까 패ㅆ..)
예시 : https://github.com/AutoParams/AutoParams#customization-annotation
4) autoparams-mockito
- 만약 데이터 값을 세팅해줘야하는 객체가, 인터페이스를 타입으로 가지고 있는 추상클래스라면 이것또한 Mocking 할 수 있다고 합니다.
- 정말 꼼꼼하게 만드셨네;;
예시 : https://github.com/AutoParams/AutoParams#autoparams-mockito
정말 너무 유용한 라이브러리라고 생각합니다
값을 주입해준다는게 조금 무섭긴한데, 일단은 Test 코드를 작성하는 시간이 많이 단축될거 같아 유용하게 사용하게 될거 같습니다!
이런거 만들어준 CTO 님 진짜 대단하다;; 👍
끁!
*참고
https://github.com/AutoParams/AutoParams