테스트 데이터 구성하기에 용이한 Easy Radom 라이브러리에 대해 글을 써보고자 한다.
본론으로 들어가기 앞서, 테스트 코드를 짜다보면 데이터를 구성하는게 생각보다 힘들다..(아니 귀찮다)
물론 각자마다 테스트용 데이터를 구성하는 방법도 여러가지겠지만 그것마저 귀찮다 싶을땐,
Easy Random이라는 library를 사용해보는 걸 추천한다! 현업에서도 팀원들에게 공유해 사용중인데 편하게 잘 쓰이고 있다.
본론으로 들어와 간단하게 테스트 코드를 위한 준비 및 사용을 위한 dependency 추가를 진행한다.
gradle 기준
testImplementation 'org.jeasy:easy-random-core:5.0.0'
maven 기준
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-random-core</artifactId>
<version>5.0.0</version>
<scope>test</scope>
</dependency>
example
전체 멤버를 조회시 5인 이상일시 정상 동작하는 코드가 있다고 가정을 해보자.
package com.example.demo;
import java.util.List;
public class ExampleService {
private final ExampleRepository exampleRepository;
public ExampleService(ExampleRepository exampleRepository) {
this.exampleRepository = exampleRepository;
}
public List<Member> getMemberList() {
List<Member> memberList = exampleRepository.findAll();
if(memberList.size() < 5) {
throw new RuntimeException("가입한 멤버수가 5인 이하네요.. 분발하세요");
}
return memberList;
}
}
package com.example.demo;
import java.util.List;
public interface ExampleRepository {
List<Member> findAll();
}
package com.example.demo;
import lombok.Data;
import lombok.Getter;
import java.time.LocalDate;
@Data
public class Member {
private String name;
private int age;
private boolean isAdult;
private Gender gender;
private LocalDate birthday;
@Getter
enum Gender {
MALE,
FEMALE
}
}
UnitTest
package com.example.demo;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class ExampleServiceTest {
@Mock
ExampleRepository exampleRepository;
@InjectMocks
ExampleService exampleService;
@DisplayName("전체멤버 조회시 5인 이상이면 통과")
@Test
void getMemberList() {
//given
List<Member> memberList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Member member = new Member();
member.setName("테스터" + i);
member.setAge(4 * i);
member.setBirthday(LocalDate.now().minusYears((long)i));
member.setAdult(true);
member.setGender(Member.Gender.MALE);
memberList.add(member);
}
given(exampleRepository.findAll()).willReturn(memberList);
//when
List<Member> result = exampleService.getMemberList();
//then
assertThat(result.size()).isEqualTo(5);
verify(exampleRepository, times(1)).findAll();
result.forEach(System.out::println);
}
}
위의 예제처럼 Mocking하기 위해 직접 구성하거나 여러건은 loop를 활용해 데이터 구성하는 경우가 생각보다 많다.
그런데 Easy Random을 활용하면???
UnitTest
package com.example.demo;
import org.jeasy.random.EasyRandom;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class ExampleServiceTest {
@Mock
ExampleRepository exampleRepository;
@InjectMocks
ExampleService exampleService;
@DisplayName("Easy Random으로 구성된 멤버조회")
@Test
void getMemberListByEasyRandom() {
//given
EasyRandom easyRandom = new EasyRandom();
List<Member> memberList = easyRandom.objects(Member.class, 5)
.collect(Collectors.toList());
given(exampleRepository.findAll()).willReturn(memberList);
//when
List<Member> result = exampleService.getMemberList();
//then
assertThat(result.size()).isEqualTo(5);
verify(exampleRepository, times(1)).findAll();
result.forEach(System.out::println);
}
}
적용 후 코드를 살펴보면 이전과는 다르게 for loop 및 값 주입이 사라지니 코드라인도 줄고 깔끔한 느낌을 준다.
사용법은 간단하다,
EasyRandom 객체 생성 후 objects() 혹은 nextObjects() 메소드를 호출해 주입할 Type, size를 넣어주면 그에 해당하는 타입의 사이즈만큼 값이 생성된다.
결과값은 아래와 같다.

어떤식으로 필드의 타입을 추론해 값을 주입을 해주는지 궁금하여 EasyRandom 구현체 내부 코드를 따라가보니,리플렉션 기반으로 필드의 타입에 따라 각각 context를 생성해주는 방식으로 돌아가는 코드였다.

+ 추가로 각각 필드의 셋팅값 range 지정등을 위해서라면 RandomizerProvider interface 구현체를 이용해 커스텀할수 있는것도 제공해 주는걸로 보인다.

글재주가 없어서 잘 전달이 됐을진 모르겠지만, 공유차 적었는데 도움이 됐으면 싶다~~~~~
참고
'개발' 카테고리의 다른 글
| [spring] OpenFeign 로그 사용자화 (0) | 2023.08.30 |
|---|---|
| spring-boot docker-compose 사용법 (1) | 2023.05.14 |
| [후기] NHN forward 2022 (0) | 2022.11.26 |
| 서비스형 재해복구 (0) | 2022.10.25 |
| flyway를 이용한 db migration (0) | 2022.10.05 |