애플리케이션 내 로직을 테스트하기 위해서 테스트 데이터를 초기화하는 방법으로 2가지를 찾았다. 첫 번째는 CommandLineRunner를 활용하는 것이고, 두 번째는 @PostConstruct를 쓰는 것이다.
CommandLineRunner는 application context가 완전히 로딩된 후에 미리 작성해 놓은 코드를 실행하는 인터페이스다.
//...
@EnableJpaAuditing
@SpringBootApplication
public class WhatachadApplication {
public static void main(String[] args) {
SpringApplication.run(WhatachadApplication.class, args);
}
@Order(value = 1)
@Bean
public CommandLineRunner adminUser(UserService userService, PasswordEncoder passwordEncoder) {
return args -> {
User user = User.builder()
.id(AuthConstant.ADMIN_USER)
.password(passwordEncoder.encode(AuthConstant.ADMIN_PWD))
.email("[email protected]")
.name("master")
.phone("01012345678")
.meta(new HashMap<>())
.build();
user.getMeta().put(UserMetaType.ROLE, UserRoleType.ROLE_ADMIN.name());
userService.createUser(user);
};
}
@Order(value = 2)
@Bean
public CommandLineRunner initTestData(FacilityRepository facilityRepository, UserService userService) {
return args -> {
String[] title = new String[]{"영휘트니스헬스클럽", "짐박스피트니스 신림역점", "자마이카짐", "에이오짐", "파운드짐 신림역점", "익스트림에스 신림"};
double[][] latLng = new double[][]{
{37.4846553, 126.9272265},
{37.4832519, 126.9287583},
{37.484787, 126.9300366},
{37.4851178, 126.9302344},
{37.4854721, 126.9299512},
{37.484847, 126.9328386}
};
User adminUser = userService.getUser("admin");
IntStream.range(0, 6)
.forEach(i -> {
FacilityDto facilityDto = FacilityDto.builder()
.address(Address.builder()
.latitude(latLng[i][0])
.longitude(latLng[i][1])
.build())
.category(FacilityType.HEALTH)
.title(title[i])
.build();
facilityRepository.save(Facility.create(adminUser, facilityDto));
});
};
}
}
그래서 테스트 데이터를 초기화하는 로직을 위와 같이 run() 메서드 내부에서 구현하면 애플리케이션 로딩 직후에 이루어진다. 하지만 위의 코드처럼 main() 메서드 아래에 해당 로직을 추가하니 굉장히 지저분한 느낌이다. 그래서 클래스를 분리하여 CommandLineRunner를 구현하는 방법이 있다.
하지만 이번에는 @PostConstruct로 시도해보겠다. 초기화 메서드 위에 @PostConstruct 어노테이션을 달아주면, Spring Bean이 생성되고 필요한 의존관계를 주입받은 후에 즉시 해당 메서드가 실행된다. 그래서 CommandLineRunner를 썼을 때와 실행 시점이 약간 다르다는 것을 유의하며 사용해야 한다.
//...
@Component
@RequiredArgsConstructor
public class TestInit {
private final UserService userService;
private final PasswordEncoder passwordEncoder;
private final FacilityRepository facilityRepository;
@Order(value = 1)
@PostConstruct
void initAdminUser() {
User user = User.builder()
.id(AuthConstant.ADMIN_USER)
.password(passwordEncoder.encode(AuthConstant.ADMIN_PWD))
.email("[email protected]")
.name("master")
.phone("01012345678")
.meta(new HashMap<>())
.build();
user.getMeta().put(UserMetaType.ROLE, UserRoleType.ROLE_ADMIN.name());
userService.createUser(user);
}
@Order(value = 2)
@PostConstruct
void initTestFacilities() {
String[] title = new String[]{"영휘트니스", "짐박스피트니스 신림역점", "자마이카 피트니스 신림역점", "스포애니 보라매점", "파운드짐 신림역점", "익스트림에스 신림점", "짐인더하우 2호점"};
double[][] latLng = new double[][]{
{37.4846553, 126.9272265},
{37.4832519, 126.9287583},
{37.484787, 126.9300366},
{37.489879, 126.9271118},
{37.4854721, 126.9299512},
{37.484847, 126.9328386},
{37.4905415, 126.9270999}
};
String[][] address = new String[][]{
{"서울특별시 관악구 신림로 206", "서울특별시 관악구 신림동 96-3", "1162010200"},
{"서울특별시 관악구 신림로59길 14", "서울특별시 관악구 신림동 1640-31", "1162010200"},
{"서울특별시 관악구 신림로 340", "서울특별시 관악구 신림동 1422-5", "1162010200"},
{"서울특별시 관악구 봉천로 227", "서울특별시 관악구 봉천동 972-5", "1162010100"},
{"서울특별시 관악구 신림로 350", "서울특별시 관악구 신림동 1424-28", "1162010200"},
{"서울특별시 관악구 남부순환로 1641", "서울특별시 관악구 신림동 1412-3", "1162010200"},
{"서울특별시 관악구 보라매로 13", "서울특별시 관악구 봉천동 702-49", "1162010100"}
};
User adminUser = userService.getUser("admin");
IntStream.range(0, title.length)
.forEach(i -> {
FacilityDto facilityDto = FacilityDto.builder()
.address(Address.builder()
.jibunAddress(address[i][0])
.roadAddress(address[i][1])
.regionCode(address[i][2])
.latitude(latLng[i][0])
.longitude(latLng[i][1])
.build())
.category(FacilityType.HEALTH)
.title(title[i])
.build();
facilityRepository.save(Facility.create(adminUser, facilityDto));
});
}
}
이와 같은 방법으로 테스트 데이터를 초기화할 수 있다. 그 외 다른 방법으로는 직접 sql script를 작성해서 초기화하는 방법도 존재한다.