Test Double

Soondol·2024년 3월 21일

TDD에 대해 공부하던 중 Stub 과 Mock의 개념에 대해 인지하게되었다.

간략히 찾아보았을때
Stub은 테스트 중 필요한 외부 의존성을 대체하고,
Mock은 테스트 중 객체간의 상호작용을 확인하거나 제어한다.

음.....

두가지가 어떻게 쓰이고 어떤 역할을 하는지
정확한 개념을 알아보고자 찾아보게되었다.

위 개념을 이해하기 위해선 Test Double에 대한 이해가 필요하다 !

Test Double

테스트를 진행하기 어려운 경우 이를 대신해 테스트를 진행할 수 있도록 만들어주는 객체
Dummy, Stub, Spy, Mock, Fake


만약 PaymentCallbackImpl의 pay 메소드가 실행되면 실제로 결제된다는 아래의 가상의 상황에서 각각의 test double을 이해해보자 !

public static void main(String[] args) {
    // 총 금액
    int totalAmount = 100;
    // PaymentService에서 실제 동작하게끔하기
    PaymentServiceImpl paymentService = new PaymentServiceImpl();
    // PaymentCallback 객체 생성
    PaymentCallback callback = new PaymentCallbackImpl();
    // 실제 주문 처리
	paymentService.processPayment(totalAmount, callback);
}
public interface PaymentService {
    void processPayment(int amount, PaymentCallback callback);
}
public class PaymentServiceImpl implements PaymentService {
    @Override
    public void processPayment (int amount, PaymentCallback callback) {
        callback.pay(amount);
    }
}
public interface PaymentCallback {
    void pay(int amount);
}
public class PaymentCallbackImpl implements PaymentCallback {
    @Override
    public void pay(int amount){
        System.out.printf("실제로 %d 원이 결제됩니다", amount);
    }
}

Dummy

아무런 동작도 하지 않음
인터페이스를 따르기 위해 매개변수의 자리를 차지하기 위해 사용
주로 파라미터로 전달되기 위함

@Test
public void payDummyTest() {
    int totalAmount = 100;
    PaymentServiceImpl paymentService = new PaymentServiceImpl();
    // 람다식을 이용한 Dummy 객체 생성
    PaymentCallback callback = amount -> {
        // 이 Dummy 객체는 아무 동작도 하지 않습니다.
    };
    paymentService.processPayment(totalAmount, callback);
}

위와같은 Dummy 객체로 실제 결제가 동작하는 부분을 대신 끼워 맞춰 동작을 테스트 한다 !
dummy에 대해 이해해보고자 예시를 작성해봤는데 들어맞는지는 모르겠다..

Stub

특정 메소드가 호출될 때 고정된 값을 반환하도록 설정하는 객체
외부 의존성을 대체하여 테스트를 간단히 만들거나
특정 조건에 따른 다양한 동작을 테스트하는데 사용

private class PaymentServiceStub implements PaymentService {
    @Override
    public void processPayment(int amount, PaymentCallback callback) {
        // 테스트 시나리오에 따라 성공 또는 실패를 시뮬레이션
        if (amount >= 0) {
            callback.pay(amount);
        } else {
            throw new RuntimeException("결제 실패: 유효하지 않은 금액");
        }
    }
}
@Test
public void payTest_success() {
    int totalAmount = 100;        
    // Stub 객체 생성 (람다식 이용)
    PaymentCallback stubCallback = amount -> {
        // 결제 성공을 시뮬레이션
        System.out.printf("결제 성공: %d 원이 결제됩니다\n", amount);
    };
    PaymentService paymentService = new PaymentServiceStub();
    paymentService.processPayment(totalAmount, stubCallback);        
}

Stub에 대해 작성하다보니 Dummy가 실제 동작하는 것 처럼 보이게 만드는것이 아닐까 라는 생각이 들었다.

Spy

Spy는 실제 객체를 감시하여 호출된 메서드의 인자나 호출 횟수 등을 기록하는 객체

// PaymentCallback의 pay 메서드가 정확히 한 번 호출되는지 확인하는 Spy 테스트
@Test
public void CallPayOnceSpyTest() {
    int totalAmount = 100;
    PaymentCallback callback = spy(new PaymentCallbackImpl());
    PaymentService paymentService = new PaymentServiceImpl();
    paymentService.processPayment(totalAmount, callback);        
    verify(callback, times(1)).pay(totalAmount); // pay 메서드가 정확히 한 번 호출되었는지 검증
}

위의 경우는 테스트를 실행해볼경우 실제 결제가 이루어질것이다.
Mock 객체를 생성하는 방법을 통해 실제 결제가 이루어지지않도록 테스트하자 !

Mock

특정 행위를 시뮬레이션하고 테스트 중에 특정 조건이나 행위를 검증하는 객체
테스트를 위한 가짜 객체를 생성

@Mock
PaymentCallback mockCallback;
@Test
public void testProcessPayment_Success() {
    int totalAmount = 100;        
    PaymentService paymentService = new PaymentServiceImpl();
    paymentService.processPayment(totalAmount, mockCallback);
    verify(mockCallback).pay(totalAmount); // pay 메서드가 호출되었는지 검증
    }
}

@Mock 어노테이션 사용 혹은
mock(classname.class) 이용하여 Mock 객체를 생성한다 !

Fake

실제 동작하는 것처럼 보이지만 실제로 동작하지 않는 가짜 객체

@Test
public void testProcessPayment_Success() {
    int totalAmount = 100;
    PaymentCallback fakeCallback = new FakePaymentCallbackImpl();
    PaymentService paymentService = new PaymentServiceImpl();
    paymentService.processPayment(totalAmount, fakeCallback);
}

?????????? dummy랑 똑같나 ??????????
목적과 동작에 차이가 있다 !

  • Dummy는 단순히 값을 전달하기 위해 사용, 아무런 동작도 하지 않음.
  • Fake는 실제 동작이나 데이터 저장을 위해 경량화된 형태로 구현되어 실제 객체와 유사한 동작을 제공.

0개의 댓글