MemberRegisterTest에서 @SpringBootTest 질문
MemberRegisterTest를 진행할 때 @SpringBootTest를 사용해서 테스트를 진행했는데요
서비스 테스트에는 @ExtendWith(MockitoExtension.class)를 사용하는 경우를 많이 봤습니다
헥사고날 아키텍처에서는 애플리케이션과 도메인이 중심이 되기 때문에 서비스에서 @SpringBootTest를 사용한걸까요?
답변 1
2
그건 아닙니다. 테스트 작성과 수행에 유리하기 때문에 선택한 방법입니다.
Repository나 EmailSender와 같은 기능 요구 인터페이스를 이용하는 애플리케이션의 내의 코드를 테스트하려면 실제 그 인터페이스 타입의 동작하는 오브젝트가 필요합니다. 그러려면 이 인터페이스를 구현한 클래스가 필요한데, 이걸 실제 어댑터 클래스를 가져다 쓰면 테스트에서도 환경에 종속이 되버릴 수가 있습니다. 그래서 테스트를 위해서 이 인터페이스를 구현한, 테스트 더블(대역) 오브젝트를 생성해야 하죠.
이때 사용하는 방식이 스텁, 목 같은 것입니다. 제가 애플리케이션 서비스 테스트를 만드는 방법을 여러가지 보여드렸는데, 가장 단순하게는 테스트 내에 그 인터페이스를 구현한 스텁이나 목 기능을 가진 클래스를 직접 만드는 것입니다. 명확하고 쉽긴 하지만 인터페이스의 기능이 많아지면 테스트를 위해서 많은 양의 코드를 작성해야 합니다. 심지어는 테스트 코드보다도 더 많은 양이 필요하죠.
그래서 특별한 경우를 제외하면 기능 요구 인터페이스의 테스트용 오브젝트는 말씀하신 Mockito 같은 손쉬운 목/스텁 오브젝트 생성 프레임워크의 도움을 받습니다. 리포지토리도 JPA를 사용했을 때 주고 받을 정보를 가정해서 그걸로 목 오브젝트를 설정할 수 있습니다.
문제는 리포지토리처럼 DB를 다루는 인터페이스는 스텁으로 넣어줘야 할 정보가 꽤 많습니다. 엔티티가 점점 커지고 조회할 정보가 많아지면 그걸 매번 Mockio 등으로 세팅하는 것도 제법 큰 일입니다. 그런데다가 등록 후에 조회와 같이 정확하게 DB처럼 동작해야 로직이 바르게 수행되고, 그래야 최종 테스트가 의미있는 상황을 만들려면 꽤나 손이 많이 갑니다.
그래서 이런 경우 스프링에서 권장하는 방식은 목 대신 페이크 오브젝트를 이용하는 것인데, 여기서는 메모리 DB(H2)를 실제 DB 대신 사용하는 가상의 기능을 수행하는 오브젝트로 쓰는 것이죠. 거기에 Spring Data가 지원해주는 리포지토리 구현 자동화까지 결합하면, 실제 운영에서 쓸 DB는 아니지만 그와 거의 유사한 방식으로 동작하는 DB까지 동작하게 해서 테스트를 만들 수 있습니다. 이게 주는 장점이 많기 때문에 스프링/부트에서도 핵심 테스트 기능으로 지원합니다.
DB와 관련 작업을 Mockito로 대체해서 만들어서 테스트하는 방식으로는 JPA의 모델이 바르게 설정되어있는지에 대한 검증이 안 되기 때문에, 이건 또 DB까지 연결하는 방식의 테스트를 따로 만들어야 하고, 이게 테스트마다 동일한 방식으로 셋업되고 동작하게 하려면 매우 큰 수고가 필요합니다.
테스트를 만드는 비용이 증가하고 시간이 많이 걸리면, 자연스럽게 테스트를 안 만들게 됩니다. 그래서 저는 JPA를 사용하는 경우 메모리 DB를 이용한 스프링의 테스트 지원 기능을 적극적으로 사용합니다. 그렇게 해도 충분히 도메인과 애플리케이션 서비스 로직에 충실한 테스트를 만들 수 있습니다.
그 외의 특별한 겻우라면 Mockito을 활용한 테스트를 사용할 수 있습니다. 다만, Mockito를 쓰는 경우에 목 오브젝트를 동적으로 만들려면 테스트 진행에 부하가 걸립니다. 그래서 테스트 실행 속도에 영햣을 주기도 합니다. Mickto와 Spring Test의 Mockito 관련 문서를 잘 보고, 성능에 영향을 최소한으로 주도록 하는 방법을 살펴보는 것이 중요합니다.
도메인 모델에서 관계와 규칙을 구분하는 방법
0
37
2
헥사고날 아키텍처에서의 배치, 시큐리티, 비동기 이벤트 처리는 어떻게 하나요?
0
115
2
어댑터에서 도메인에 직접 의존하는 경우에 대해
0
116
2
Member 도메인이 PasswordEncoder를 받는 구조 질문 있습니다.
0
103
2
MemberService와 EmailSender 책임 분리에 대한 질문
0
102
2
NonNullApi를 NullMarked로 대체하라고 합니다.
0
123
2
39. 문서와 코드 다듬기 updateInfo 테스트 질문 있습니다.
0
71
2
Repository Adapter 설계에 대해 피드백을 부탁드립니다
0
105
2
헥사고날 part2 강의 출시 예정일 문의 드립니다.
0
244
2
PT 문의사항
0
97
1
초기 어플리케이션 구동 시 compose.yml 파싱 오류
0
147
2
애플리케이션의 JPA 리턴과 도메인 모델
0
125
2
애그리거트 루트의 하위 도메인들의 depth가 깊어질 때 문의
0
133
2
페이징 처리를 해야한다면 어떻게 해야할까요?
0
187
2
애그리거트의 repository
0
116
2
Domain Expert가 정확히 어떤 역할을 하는 사람인가요?
0
228
1
회원 애플리케이션 서비스 테스트 (1)
0
102
2
정적 팩토리 메서드 관련 질문드립니다!
0
103
2
spotbug + @NonNullApi 로만 Null 방어가 될까요?
0
127
2
required 포트에 관해서
0
90
2
혹시 다음 편은 언제쯤 오픈할까요?
0
163
2
서비스 단위 테스트 코드 작성
0
94
2
domain 모듈에 entity를 정의한다고 했을때
0
95
2
여러 엔티티의 조합으로 리포트를 제공해야할 때
0
78
2





