오늘은 정말 힘든 하루였다. 정말 왠만해선 짜증을 내지 않는 내 자신이 원인모를 짜증으로 정말 힘들었다. 아직도 원인을 잘 모르겠는데, 지금 오늘 하루를 기록하는 이 순간에도 속어디선가 화가 들끓는다... 운동으로 풀어보려했으나, 풀리지 않았다.. 개발로 풀어보려했으나 개발로도 풀리지 않았다.. 오히려 운동도, 개발도 모두 잘 안됬다. 지금 돌이켜보면 정말 많이 쉽지 않은 하루였던 것 같다.
테스트에 관하여
오늘은 테스트에 하루개발시간을 거의 다 소모했다. 컨디션 문제도 있었지만, 테스트와 관련하여 이슈와 고민때문에 아주 많은 시간을 소비하게 된 것 같다.
오늘은 Application 계층의 API 를 모두 구현하고, 테스트하는 것이 목표였다. API 는 Order 생성, Order 조회 이었기 때문에 매우 간단했기 때문에 충분히 테스트를 진행하며 개발을 이어 갈 수 있을 것이라 생각했다. (하지만 테스트에서 발목을 잡혔다지)
테스트를 하는 클래스에서 사용하는 클래스는 어떻게 해야할까?
나는 테스트를 진행하는 클래스에서 사용하는 (의존성 주입된)모든 클래스는 Mocking하여, Stub 처리하는 것이 맞다고 생각하고 있다. 그런데 오늘 큰 고민이 된 부분이 생겼다. 특정 클래스의 처리를 위임한 클래스라면?
나는 CommandService 를 개발하면서 이 고민이 시작되었다.
나는 유스케이스를 크게 Command(상태변경), Query(조회)로 분류하고, 각 서비스에서 이를 처리하도록 하였다. 서비스는 1차 분류된 유스케이스에 따라 또 다시 Handler로 나눠진다. 즉, 각 유스케이스는 최종적으로 Handler 에서 다뤄진다.
주문 생성 유스케이스를 담당하는 CreateOrderCommandHandler 는 가독성을 위해 OrderCreateHelper 클래스를 생성자를 통해 주입받고, createOrder 를 간단하게 표현한다.
이제 주문 생성 유스케이스를 구현하기 위해서는 OrderCreateHelper 클래스를 먼저 테스트하고 기능을 구현해야한다. 그리고 나는 여기서 많은 고민을 하게 되었다.
가만보면, 사용하는 모든 클래스를 Mocking 및 Stub 하고있다. 해당 로직에서의 과정들을 모두 Stub(내가 원하는 답을 작성) 하는데 이것이 의미가 있는걸까? 하는 생각이 들었다. 그러면서 동시에, 내가 테스트를 하고자하는 목적이 뭐지? 이 메서드를 개발하는데 테스트를 잘못작성하는 것은 아닌가? 하는 생각이 들면서 이글의 처음으로 돌아가고 다시 지금으로 돌아기를 반복했다.
결국 나는 이 테스트가 불필요하다 판단했다. CommandService에서 CommandHandler 를 호출하고, CommandHandler에서 Helper 를 호출하면서 자연스럽게 검증이 되어 불필요하다 생각했기 때문이다. 하지만 한편으로는 이렇게 내가 원하는 데이터들로 Mocking 및 Stub 하더라도 작성하는 것이 맞는것인지... 헷갈린다..
그렇게 나는 OrderCommandService 테스트를 작성하며, OrderCommandHandler 를 개발했다.
중간중간 솓구치는 화때문에 정말 힘들었지만, 하나의 유스케이스를 개발하는데 거진 4시간이 걸렸다.. 하지만 화는 여전히 계속됬고, 이후 OrderQueryService 를 구현하는데에도 큰 영향(?)을 주었다.
OrderQueryService 테스트간 발생한 오류
OrderQueryService 또한 개발해야 할 API는 주문 조회 기능 한가지 이다. QueryService 는 이전 CommandService에서 고민했던 부분들이 없어 진짜 10분도 안걸리게 개발할 수 있을것이라 생각했다. 그리고 언제나 이러한 거만은 화를 불렀다.(오늘은 안그래도 넘쳐 흘렀는데 말이다..)
CommandService 에서는마찬가지로 Handler에 해당 유스케이스를 다루도록 책임을 위임한다. 그리고 나는 Handler 를 Stub 하여, 원하는 데이터를 가져올 것으로 예상하며, 테스트 코드를 작성했다.
그리고 TrackOrderQueryHandler 에서 trackOrder 를 통해 상호작용했음을 검증하는 것으로, 내가 원하는 동작을 할 것임을 검증하고자 하였다. 하지만 문제가 발생하였다.
테스트 실행결과는 정말 당황스러웠다. Hanlder내의 trackOrder() 가 호출이 되지 않는다니..? 말이 되지 않는다. 분명 내가 작성한 QueryService 에서는 Handler 의 trackOrder() 를 호출하는데... 너무 이상했다.
나는 바로 Print 를 통해 확인해 보았다.
나는 더 큰 의문에 빠졌다. 정상적으로 해당 메서드를 호출하는데, 호출되지 않았다니..? 또 다시 한참을 고민하고 코드를 다시 차분히 보면서 문제의 원인을 알 수 있었다.
그냥 문득 SpringBootTest 인데 왜 MockBean 을 사용하지 않았지? 하는 생각이 들어 Mock 부분을 MockBean 으로 변경해보았다. 그리고 신기하게 문제는 해결되었다.
나는 둘의 차이를 확인하기 위해 각각 상황에 맞춰 trackOrderQueryHandler 를 print 해보았다.
결과는 크게 차이가 없었다.(?) 그래서 해당 차이가 궁금해서 GPT에게 물어보았다.
@Mock, @MockBean
요약하자면, @Mock 은 Mockito 기반의 단위테스트에서 Mock 객체를 만들 때 사용되며, @MockBean 은 Spring Boot 통합 테스트에서 Spring MockBean 을 생성하는데 사용된다. 이 둘 사이의 선택은 작성중인 테스트가 Spring 컨텍스트 내 구성 요소의 상호작용을 테스트하는지, 혹은 격리된 단위테스트에 집중하는지에 따라 달라진다고 한다.
다시 지난 QueryService 테스트를 본다면, 나는 Spring 컨텍스트 내 구성요소간의 상호작용을 테스트하기에 @Mock 이 아닌 @MockBean 을 사용했어야 했던 것이다.
이에 대한 내용은 처음 알게되어, 테스트에 관한 내용을 정리하면서 함께 작성해야겠다.
오늘은 정말 많이 속상하다. 내 자신에게도 화를 다스리지 못해 속상하고, 계획한 일정을 지키지 못해 속상하다. 내 자신에 반성하고, 내일은 오늘보다 나은 내일이 될 수 있었으면 좋겠다.
'회고 > TIL' 카테고리의 다른 글
드디어 메시징 테스트 진행, 거의 다 온 것 같다(?)[ 3AM, 문제해결 ] (0) | 2023.08.19 |
---|---|
Application 계층 완료, Adapter 개발시작, 디자인패턴공부 (0) | 2023.08.17 |
독서: 개발 프로세스에 관하여, 애플리케이션 계층 개발, 에러 (0) | 2023.08.14 |
Order 도메인 계층 병합, 디자인 패턴 공부, 온라인 피드백 (0) | 2023.08.13 |
Order 도메인 계층 완료, 재밌는 독서 (0) | 2023.08.12 |