백엔드 클린코드, 테스트코드 회고 4주차 마지막
해당 회고는 'Practical Testing: 실용적인 테스트 가이드' 강의에 대한 회고입니다.
마지막 주
벌써 4주 동안의 스터디가 끝났습니다. 그래도 무언가 마무리된다는 것은 보람차면서도 아쉽네요.
이번주에 한 것들을 정리하면서 마지막 회고를 작성해보겠습니다!
배운 것들
4주차에서는 Mockito와 관련된 사용과 stubbing하는 방법, 더 나은 테스트 작성하기, 학습 테스트와 Spring REST docs를 공부했습니다.
Mockito로 Stubbing하기
추가 기능으로 날짜와 이메일을 받고 일 총 매출 이메일로 전송해주는 것을 구현
외부 네트워크를 타는 로직의 경우 실제 메일을 전송하는 것까지 테스트에 포함시켜야 할까?
할 필요가 없다 시간과 비용적인 낭비다
적절한 mocking으로 원활한 테스트를 가능하게 해보자!
@MockBean
private MailSendClient mailSendClient;
@DisplayName("결제 완료 주문들을 조회하여 매출 통계 메일을 전송한다.")
@Test
void sendOrderStatisticsMail() {
//given
...
when(mailSendClient.sendEmail(any(String.class), any(String.class), any(String.class), any(String.class)))
.thenReturn(true);
//when
...
}
Test Double
stub과 Mock이 헷갈렸는데 바로 알게되었다.
둘의 공통점은 어떤 행위에 대한 결과를 정해두고 그것을 리턴해주는 것
차이점은 검증 목적이다. Stub은 테스트를 함에 따라 변한 상태를 검증하는 것, 테스트 후에 Stub의 상태가 어떻게 변했는지 주목
Mock은 테스트를 함에 따라 동작하는 행위를 검증하는 것, 테스트를 하면 어떤 동작이 실행될 것인지에 대해서 주목
순수 Mokito Extension으로 사용해보기, 어노테이션 사용해보기
Mock과 Spy의 차이를 명확하게 공부하고 직접 함수를 이용해봤다. 외에도 @MockBean, @SpyBean, @InjectMocks도 학습했다.
BDDMokito
Mock을 사용할 때 when 함수의 경우 표기상 when절에 있는 것이 맞을 것 같은데 given절에 있어서 뭔가 표현이 매끄럽지 않은 것 같다.
따라서 나온 것이 BDDMockito.
모든 동작은 Mockito와 동일하다 BDD스타일로 이름만 변경한 것.
앞으로 Mockito를 작성할 때는 given절에서 BDDMockito를 적극적으로 이용하자!
given절에 구현되는 when절을 BDDMockito.given()으로 사용할 수 있도록 해줘서 매끄러운 표현을 할 수 있도록 해준다.
@DisplayName("메일 전송 테스트")
@Test
void sendMail() {
//given
BDDMockito.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString()))
.willReturn(true);
//when
boolean result = mailService.sendMail("", "", "", "");
Classicist vs Mockist
Mockist는
Mock으로 모든 테스트를 커버하고 보장이 된 부분에 대해서는 Mocking처리를 해서 빠른 테스트를 진행하자는 주의
Classicist는 실제 프로덕션 코드에서 잘 돌아간다는 보장을 하기 위해서 실제 객체로 최대한 테스트를 진행해야 하고 꼭 필요한 경우에만 Mocking을 진행하자는 주의
만약 프로덕션 레벨에서 테스트의 유효성이 Mockist가 낮다면 Classicist를 따르는 것이 맞을 것 같은데 규모가 작거나 커버리지 퍼센트를 어느정도 유지하고 싶다면 Mockist 방법을 택해서 할 수도 있을 것 같다.
나은 테스트를 위한 조언
하나의 문단에 하나의 주제를 가지는 것이 좋은 글쓰기인 것처럼 각 테스트메서드는 하나의 주제만 가지는 것이 바람직
테스트 환경을 조성할 때 모든 환경을 제어할 수 있어야 한다.
given절에서 테스트 기반 환경을 세팅할 때 다른 테스트와 결합이 생기지 않도록 독립적으로 작성하자
두가지 이상의 테스트가 하나의 공유변수를 이용할 때 한 테스트가 변수의 상태를 바꾼다면 다른 테스트의 결과를 보장할 수 없다.
여러가지 테스트 메서드를 정의했을 때 given에 겹치는 데이터가 생각보다 많다.
문서로써의 테스트 기능을 잘 수행하도록 잘 분배해보자
성능과 시간적으로 효율적이고 일괄 삭제를 해주는 deleteAllInBatch를 사용하자
파라미터에 여러값을 적용해서 테스트할 수 있는 @ParameterizedTest와 공유변수로 다수의 테스트를 수행할 수 있는 @DynamicTest
테스트 환경도 상위에서 관리할 수 있게 해서 환경을 통합 관리하자
private 메서드 테스트를 하고 싶다면 객체 분리의 시점으로 보자. 하나의 퍼블릭 메서드에서 하는일이 너무 많은지 확인해보고 프라이빗 메서드의 기능을 별도의 객체에 위임하는 방법을 고려하자
프로덕션 코드에서는 필요없는 테스트 코드에서만 사용하는 최소의 생성자나 빌더는 필요에 의한 최소범위로 만들고 무분별한 생성을 지양하자
학습테스트
학습테스트는 테스트를 학습의 용도로 이용하는 것이다.
Guava라는 라이브러리를 테스트메서드로 학습해보았다. 실제 동작적인 확인을 하기에 매우 좋은 것 같고 뭔가 나만의 동적인 Docs를 남기고 공유하고 싶을 때 이용하기 좋은 방법인 것 같다.
Spring REST Docs
프로젝트 때 비슷한 swagger를 사용해봤다. 제대로 잘 익혀놓으면 다음 개발때 잘 이용해 볼 수 있을 것 같다.
진짜 마무리 회고
많은 분들에게 동기부여받고 학습했던 한 달이었습니다. 배움에는 끝이 없다는 것을 늘 느끼고 앞으로도 꾸준히 열심히 도전하고 학습하고 싶습니다. 인프런 워밍업 클럽 짱
댓글을 작성해보세요.