추가적으로 조금 더 자세히 정리할 예정입니다.
단위 테스트를 작성하기 위하여 Mock 객체에 대하여 학습을 진행하고 포스팅한 글입니다.
단위 테스트는 특정 단위(테스트 대상)가 의도한대로 작동하는지 검증하는 것이다.
단위 테스트 작성 시 관계를 맺고있는 대상 (협력 객체)이 있는 경우를 고려해서 테스트를 작성해야 한다.
이때, 협력 객체를 실제 객체로 사용하는지 Mock(가짜) 객체 로 사용하는지에 따라 테스트 구현이 달라진다.
테스트 대상이 협력 객체
를 가질 때
실제 객체
를 사용 하면 협력 객체의 행위를 협력 객체 스스로가 정의 한다.가짜 객체
를 사용 하면 협력 객체의 행위를 테스트가 정의 한다.그렇다면 언제 실제 객체
로 구현하고 가짜 객체
로 구현할까?
그래서 협력 객체를 실제 객체
로 테스트를 구현할 때와 , Mock 객체
를 사용하여 테스트를 구현하는 경우를 비교하고
Mock 객체에 관해 학습해보기 위해 포스팅을 진행하였다.
단일 단위 테스트 vs 협력 객체를 사용하는 단위 테스트
위의 테스트는 Station 이란 객체에 관하여만 검증을 했고, 아래의 테스트에서 Line 은 Station 에 대한 의존을 가지고 있는 것을 확인할 수 있다.@Test void updateName(){ Station 강남역 = new Station("강남역"); 강남역.updateName("교대역"); assertThat(강남역.getName()).isEqualTo("교대역"); }
@Test void addSection(){ Station 강남역 = new Station("강남역"); Station 교대역 = new Station("교대역"); Station 교대역 = new Station("역삼역"); Line line = new Line("2호선", "green", 강남역, 교대역, 10); line.addSection(교대역, 역삼역, 5); assertThat(line.getStations()) .contaionsExactlyElementsOf(Arrays.asList(강남역,교대역,역삼역)); }
Test Double이란?
위에서 설명한 가짜 객체
라고 볼 수 있다.
테스트 목적으로 실제 객체 대신 사용되는 모든 종류의 척도 객체 를 의미한다.
즉, 실제 (예 : 클래스, 모듈 또는 함수)를 가짜 버전으로 대체한다는 의미이다.
가짜 버전은 실제와 같은 것처럼 보이고 (동일한 메소드 호출에 대한 답변) 단위 테스트 시작시 스스로 정의한 미리 준비된 답변으로 답변한다. Test Double에는 다 똑같은 Test Double 이 아니라 가짜 객체를 활용하는 방식(종류)이 여러가지가 있지만 '대체 ' 한다는 큰 의미에서는 같다고 할 수 있다.
ex) fake 방식으로 처리한 test double
Stubbing 방식은 테스트 동안 호출이 되면 미리 지정된 답변으로 응답하는 것이다.
미리 프로그램된 것 외의 것에 대해서는 응답하지 않는다.
Test Double 을 사용 할 경우 테스트에서 협력 객체의 세부 구현을 알아야 한다.
때문에 stub을 하려면 세부 구현에 의존할 수 밖에 없다.
Mockito
를 활용할 경우 다음과 같이 테스트를 작성할 수 있다.@DisplayName("단위 테스트 - mockito를 활용한 가짜 협력 객체 사용") public class MockitoTest { @Test void findAllLines() { // given LineRepository lineRepository = mock(LineRepository.class); StationRepository stationRepository = mock(StationRepository.class); when(lineRepository.findAll()).thenReturn(Lists.newArrayList(new Line())); LineService lineService = new LineService(lineRepository, stationRepository); // when List<LineResponse> responses = lineService.findAllLines(); // then assertThat(responses).hasSize(1); } }
Spring
를 활용할 경우 다음과 같이 테스트를 작성할 수 있다.@DisplayName("단위 테스트 - SpringExtension을 활용한 가짜 협력 객체 사용") @ExtendWith(SpringExtension.class) public class SpringExtensionTest { @MockBean private LineRepository lineRepository; @MockBean private StationRepository stationRepository; @Test void findAllLines() { // given when(lineRepository.findAll()).thenReturn(Lists.newArrayList(new Line())); LineService lineService = new LineService(lineRepository, stationRepository); // when List<LineResponse> responses = lineService.findAllLines(); // then assertThat(responses).hasSize(1); } }
+)
Mockist의 단위 테스트는 테스트 대상을 협력 객체로 부터 격리하기 위해 테스트 대상이 의존하는 모든 것을 가짜 객체로 대체한다는 테스트 방식이다.
한 마디로, Line과 Station 모두 잘 동작하는지 검증한다는 것은 단위와 단위의 통합이 잘 동작하는지를 검증하는 것이라고 볼 수 있다.
Mockito는 Mock Object를 creation, verification, stubbing 해주는 java 라이브러리이다.
위와 관련하여 이전에 WIL 에 정리한 내용이 있다.
Mokito 를 이용한 테스트에 관하여 위의 포스팅 을 참조하면 좋을 것 같다.
하지만, 무분별한 테스트 더블을 활용한 단위 테스트 는 주의해야한다.
테스트 더블을 통한 단위 테스트는 각 Layer, Componenet 간 연동이 되어 잘 되는 것까지는 보장하지는 못할 수 있다. (ex. 연동되는 모듈들의 버그 유무 등)
또한, Mock, Stub 를 사용하면 그만큼 테스트가 구현부를 상세하게 의존하기 때문에 테스트 더블 객체들은 깨지기 쉬운 테스트 케이스가 되기 쉽다.
[참조]
우아한테크캠프 Pro 3기 - 5주차 인수테스트 기반 TDD
https://jojoldu.tistory.com/637