Spring Boot 공부 일기 <20> - Mockito, spy

이동휘·2024년 9월 13일

Spring Boot

목록 보기
19/21

1. IDE

Intellij

2. 오늘 공부 내용

Mockito, spy

Mockito 개요

  • 객체 간의 의존성을 가상(Mock) 객체로 대체하여 테스트할 수 있도록 도와줌
  • Mockito의 주요 기능
    • Mock 객체 생성: @Mock 어노테이션을 사용하여 Mock 객체를 생성하고, 특정 메서드 호출에 대한 동작을 정의합니다.
    • 스파이(Spy) 객체: 실제 객체의 특정 메서드만 모킹하고, 나머지 메서드는 실제 동작을 수행하도록 할 수 있습니다.
    • 메서드 호출 검증: 특정 메서드가 얼마나 호출되었는지 검증하고, 예상대로 동작했는지 확인할 수 있습니다.
    • 동작 정의(Stub): 특정 메서드 호출 시 가짜 데이터를 반환하도록 설정할 수 있습니다.

Mockito에서의 Mock과 Spy

  • Mock과 Spy의 차이점
MockSpy
실제 객체를 대체하여, 모든 메서드를 모킹합니다.실제 객체를 사용하고, 특정 메서드만 모킹할 수 있습니다.
모든 메서드가 Mockito에서 정의한 동작을 따릅니다.스파이된 메서드만 모킹되며, 나머지 메서드는 실제 동작을 따릅니다.
메서드 호출 및 동작을 모두 정의해야 합니다.전체 객체의 상태와 동작을 유지하면서, 선택적으로 동작을 제어할 수 있습니다.
의존성 주입된 실제 객체와는 완전히 독립적입니다.실제 객체의 일부 동작을 테스트하는 데 유리합니다.

- Mock 객체 사용하기 - @Mock 어노테이션을 사용
- 주입된 의존성을 Mock 객체로 대체하여 테스트

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void givenValidUser_whenRegister_thenUserIsSaved() {
        // Given
        User user = new User("john.doe", "password123", "john.doe@example.com");
        when(userRepository.save(any(User.class))).thenReturn(user);

        // When
        User registeredUser = userService.register(user);

        // Then
        assertNotNull(registeredUser);
        assertEquals("john.doe", registeredUser.getUsername());
        verify(userRepository, times(1)).save(user);
    }
}
  • @Mock: userRepository를 모킹하여, 데이터베이스와의 실제 상호작용 없이 테스트합니다.
  • @InjectMocks: UserService에 모킹된 UserRepository를 주입합니다.
  • when(userRepository.save(any(User.class))): save() 메서드를 호출할 때, 실제로는 Mock 객체의 가짜 데이터를 반환하도록 설정합니다.
  • verify(userRepository, times(1)).save(user): save() 메서드가 정확히 한 번 호출되었는지 검증합니다.

- Spy 객체 사용하기
- 실제 객체를 기반으로 동작하며, 객체의 일부 메서드만 모킹

@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {

    @Spy
    private OrderService orderService;

    @Test
    void givenValidOrder_whenProcessOrder_thenOrderIsProcessed() {
        // Given
        Order order = new Order("item1", 2);
        doReturn(100.0).when(orderService).calculatePrice(order);

        // When
        double price = orderService.processOrder(order);

        // Then
        assertEquals(100.0, price);
        verify(orderService, times(1)).calculatePrice(order);
    }
}
  • @Spy: 실제 OrderService 객체를 사용하면서, calculatePrice() 메서드만 모킹합니다.
  • doReturn(100.0).when(orderService).calculatePrice(order): 실제로 calculatePrice() 메서드를 호출하지 않고, 100.0을 반환하도록 설정합니다.
  • 나머지 메서드는 실제 동작을 수행하며, 전체적인 테스트 시나리오를 확인할 수 있습니다.

Given-When-Then과 Mockito의 결합

  • Mockito와 Given-When-Then을 활용한 테스트
@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {

    @Mock
    private PaymentService paymentService;

    @InjectMocks
    private OrderService orderService;

    @Test
    void givenValidOrder_whenProcessOrder_thenPaymentIsProcessed() {
        // Given
        Order order = new Order("item1", 2);
        when(paymentService.processPayment(anyDouble())).thenReturn(true);

        // When
        boolean isPaymentSuccessful = orderService.processOrder(order);

        // Then
        assertTrue(isPaymentSuccessful);
        verify(paymentService, times(1)).processPayment(anyDouble());
    }
}
  • Given: paymentServiceprocessPayment() 메서드가 항상 true를 반환하도록 모킹합니다.
  • When: processOrder() 메서드를 호출하여 주문을 처리합니다.
  • Then: 주문 처리가 성공적이며, processPayment() 메서드가 한 번 호출되었는지 검증합니다.

- Spy를 활용한 Given-When-Then 테스트

@ExtendWith(MockitoExtension.class)
public class PaymentServiceTest {

    @Spy
    private PaymentService paymentService;

    @Test
    void givenValidAmount_whenProcessPayment_thenPaymentIsProcessedSuccessfully() {
        // Given
        double amount = 200.0;
        doReturn(true).when(paymentService).validateAmount(amount);

        // When
        boolean isPaymentSuccessful = paymentService.processPayment(amount);

        // Then
        assertTrue(isPaymentSuccessful);
        verify(paymentService, times(1)).validateAmount(amount);
    }
}
  • Given: validateAmount() 메서드만 모킹하여 항상 true를 반환하도록 설정합니다.
  • When: 실제 processPayment() 메서드를 호출합니다.
  • Then: validateAmount() 메서드가 호출되었는지 검증합니다.

0개의 댓글