inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

워밍업 클럽 3기 BE 클린코드&테스트 - 4주차 발자국

양종문
0

강의 요약

섹션 7. Mock을 마주하는 자세

 

@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;

@DisplayName("메일 전송 테스트")
@Test
void sendMail() {
    // given
    when(mailSendClient.sendMail(anyString(), anyString(), anyString(), anyString()))
        .thenReturn(true);

    // when
    boolean result = mailService.sendMail("", "", "", "");

    // then
    assertThat(result).isTrue();
    verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class));
}

 

@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;

@DisplayName("메일 전송 테스트")
@Test
void sendMail() {
    // given
    BDDMockito.given(mailSendClient.sendMail(anyString(), anyString(), anyString(), anyString()))
        .willReturn(true);

    // when
    boolean result = mailService.sendMail("", "", "", "");

    // then
    assertThat(result).isTrue();
    verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class));
}

 

 

 

섹션 8. 더 나은 테스트를 작성하기 위한 구체적 조언

 

 

 

 

@DisplayName("상품 타입이 재고 관련 타입인지를 체크한다.")
@CsvSource({"HANDMADE,false", "BOTTLE,true", "BAKERY,true"})
@ParameterizedTest
void containsStockType(ProductType productType, boolean expected) {
    // given-when
    boolean result = ProductType.containsStockType(productType);

    // then
    assertThat(result).isEqualTo(expected);
}
private static Stream<Arguments> provideProductTypesForCheckingStockType() {
    return Stream.of(
        Arguments.of(ProductType.HANDMADE, false),
        Arguments.of(ProductType.BOTTLE, true),
        Arguments.of(ProductType.BAKERY, true)
    );
}

@DisplayName("상품 타입이 재고 관련 타입인지를 체크한다.")
@MethodSource("provideProductTypesForCheckingStockType")
@ParameterizedTest
void containsStockType(ProductType productType, boolean expected) {
    // given-when
    boolean result = ProductType.containsStockType(productType);

    // then
    assertThat(result).isEqualTo(expected);
}
@DisplayName("재고 차감 시나리오")
@TestFactory
Collection<DynamicTest> stockDeductionDynamicTest() {
    // given
    Stock stock = Stock.create("001", 1);

    return List.of(
        DynamicTest.dynamicTest("재고를 주어진 개수 만큼 차감할 수 있다.", () -> {
            // given
            int quantity = 1;

            // when
            stock.deductQuantity(quantity);

            // then
            assertThat(stock.getQuantity()).isZero();
        }),
        DynamicTest.dynamicTest("재고보다 많은 수의 수량으로 차감 시도하는 경우 예외가 발생한다.", () -> {
            // given
            int quantity = 1;

            // when-then
            assertThatThrownBy(() -> stock.deductQuantity(quantity))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessage("차감할 재고 수량이 없습니다.");
        })
    );
}

 

 

 

 

섹션 9. Appendix

 

 

미션 (DAY16)

미션 (DAY18)


발작국 4주차 회고

이번 주는 테스트 코드 작성과 관련된 다양한 어노테이션의 차이를 이해하고 이를 실무에 어떻게 적용할 수 있을지 고민하는 시간이었습니다. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이점을 명확히 이해하는 데 집중했으며 각각의 어노테이션이 어떤 상황에서 적합한지 학습할 수 있었습니다. 더불어 테스트 코드를 작성하며 효율성을 높이는 방법에 대해서도 많은 것을 배웠습니다. 특히 Mock 객체를 활용해 데이터베이스나 네트워크 호출과 같은 외부 시스템 의존성을 줄이는 것이 얼마나 중요한지 체감할 수 있었으며 테스트 코드를 효과적으로 작성하는 방법에 대해 다시 한번 깊이 생각하게 된 의미 있는 시간이었습니다.

백엔드 워밍업클럽

답변 0