실용적 테스트 가이드 발자국 4주차
Test Double 이란?
테스트에서 실제 객체를 대체하여 사용하는 가짜 객체(test substitute)의 총칭
Test Double은 단위 테스트 시 실제 객체 대신 사용하는 “대역 객체”입니다.
마틴 파울러(Martin Fowler)는 이를 5가지 유형으로 정리했습니다.
Dummy
아무 것도 하지 않는 깡통 객체
Fake
단순한 형태로 동일한 기능을 수행하나, 프로덕션에서는 쓰기는 부족한 객체
Stub
테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체
Spy
Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체 일부는 실제 객체 처럼 동작시키고 일분만 Stubbing 할 수 있다.
Mock
행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체
Mock과 Stub의 혼란
테스트에 대한 개인적인 생각입니다.
테스트를 작성하는 방법의 시작이 누군가에게는 마틴 파울러의 Test Double과 같은 개념에서 출발했을 수도 있지만,
대부분은 TDD(Test-Driven Development)를 가장 먼저 접하지 않을까 생각이 든다.
아래는 TDD 스타일의 테스트 코드를 chatGPT 에게 요청하여 작성된 코드이다.
// OrderTest.java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class OrderTest {
@Test
void 주문_총_금액을_계산한다() {
Product apple = new Product("사과", 1000);
Product banana = new Product("바나나", 2000);
Order order = new Order();
order.addProduct(apple);
order.addProduct(banana);
assertEquals(3000, order.totalPrice());
}
}
Product 를 Mock 를 사용하여, 테스트 코드 작성
// OrderTest.java
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
public class OrderTest {
@Test
void 주문_총_금액을_계산한다_Product_Mock_사용() {
// Arrange
Product apple = mock(Product.class);
Product banana = mock(Product.class);
when(apple.getPrice()).thenReturn(1000);
when(banana.getPrice()).thenReturn(2000);
Order order = new Order();
order.addProduct(apple);
order.addProduct(banana);
// Act & Assert
assertEquals(3000, order.totalPrice());
}
}
Mockito의 mock을 통한 테스트에 익숙해질때쯤 마틴 파울러의 test double의 stub과 mock의 혼란
자연스럽게 Mockito의 mock을 이용하여 mock 테스트 해왔다 생각했지만, test double의 stub과 mock의 혼합된 테스트를 해온것이 아닌가 생각이든다.
그러기에 stub과 mock 테스트가 명확하게 구별 된다기 보다는 같은 것이 아닌가? 라는 혼란이 오는게 아닌가 싶다.
두 테스트의 then에 해당 하는 부분에서는 상태(값)을 assertEquals(3000, order.totalPrice()); 확인하고 있다.
그렇다면 해당 두 테스트는 test double에서 이야기하는 Mock 테스트 인가? Stub 테스트인가?
주문_총_금액을_계산한다()
Product 실제 객체 사용 최종적으로 상태(값)에 대한 확인 -> Stub
주문_총_금액을_계산한다_Product_Mock_사용()
Product 부분을 Mock 하였으며, Order 객체의 totalPrice의 상태(값)을 확인 -> Mock & Stub
해당 테스트에서 상태(값) assertEquals(3000, order.totalPrice()); 을 확인 하는 것이 아닌 verify(apple).getPrice(); 이 였다면 Mock 테스트이지 않을까?
조금 더 확인이 필요할 것으로 생각이 된다.
댓글을 작성해보세요.