[Spring] Service 테스트 - ExtendWith

홍서영·2025년 12월 23일

Service Layer Test - @ExtendWith

@ExtendWith(MockitoExtension.class)을 활용하여 스프링 컨텍스트를 띄우지 않는 빠른 서비스 단위 테스트가 가능하다.

서비스 테스트 코드는 아래와 같다.

@ExtendWith(MockitoExtension.class)
@DisplayName("SellerProductService 단위 테스트")
class SellerProductServiceTest {

    @Mock
    private ProductRepository productRepository;

    @InjectMocks
    private SellerProductService sellerProductService;

    @Test
    @DisplayName("상품 등록 테스트 : 필수 정보를 포함한 상품 정보 등록 성공 확인")
    void registerProduct_Success(){
        Long sellerId=24L;

        // given
        ProductRequestDto requestDto = ProductRequestDto.builder()
            .name("겨울 긴팔 티셔츠")
            .brandName("테스트 브랜드명")
            .info("테스트 인포")
            .price(BigDecimal.valueOf(36000))
            .image("url")
            .colorGroup("밝은")
            .tags(List.of("기모", "긴팔T", "겨울", "화이트"))
            .stockQuantity(300)
            .build();

        Product mockProduct = Product.registerProduct(sellerId,requestDto);

        // stubbing
        given(productRepository.save(any(Product.class))).willReturn(mockProduct);

        // when
        ProductResponseDto responseDto = sellerProductService.registerProduct(sellerId,requestDto);

        // then
        assertThat(responseDto).isNotNull();
        assertThat(responseDto.getName()).isEqualTo("겨울 긴팔 티셔츠");
        assertThat(responseDto.getStockQuantity()).isEqualTo(300);
        assertThat(responseDto.getTags())
            .isNotNull()
            .hasSize(4)
            .contains("기모","화이트");

        verify(productRepository,times(1)).save(any(Product.class));
    }
}

@Mock은 테스트에 필요한 의존성(부품)을 가짜로 만들고 @InjectMocks을 통해 @Mock으로 만든 가짜 부품들을 테스트 대상 객체(Service 등)에 자동으로 주입한다.
ProductRepository는 테스트에는 필요하지만 실제로 사용할 것이 아니기 때문에 실제 로직은 없고 껍데기만 있는 모의 객체로서 만들고 이를 SellerProductService에 주입시켜주는 것이다.

( @WebMvcTest에서 썼던 @MockitoBean은 스프링 컨테이너가 주입해 주는 방식이고 @Mock은 Mockito 라이브러리가 순수 자바 객체 수준에서 주입해 주는 방식이다. )

< 세부 코드 설명 >

  • given : 필요한 세팅값을 미리 준비한다.
  • when : 실제 Service의 메서드를 호출해 로직을 테스트한다.
  • then : assertThat을 활용하여 응답값을 검증하고 verify를 이용해 사용된 횟수를 체크한다.

컨트롤러 테스트에서는 HTTP 응답 스펙을 효율적으로 검증할 수 있는 MockMvc의 andExpect를 사용했었는데 일반적인 로직 검증이나 복잡한 객체 비교가 필요한 서비스 테스트에서는 AssertJ의 assertThat을 사용한다.

자주 사용되는 AssertJ 메서드

동등성 검증

  • isEqualTo(expected)
  • isNotEqualTo(expected)

Null 체크 : 객체나 필드가 초기화되었는지 또는 의도적으로 비어있는 상태인지 검증할 때 사용

  • isNotNull()
  • isNull()

컬렉션 크기 및 내용 검증 : List, Set 등 컬렉션 데이터를 검증할 때 필수적

  • hasSize(size)
  • isEmpty()
  • containsExactly(elements…) → 요소가 정확히 동일한 순서와 내용으로 포함되어있는지 확인
  • contains(elements…) → 요소들이 순서에 관계 없이 포함되어있는지 확인

Boolean 검증

  • isTrue()
  • isFalse()

예외 검증

  • assertThatThrownBy(()→…) → 람다식 내부 코드가 예외를 던지는지 확인하고 예외 객체를 반환
  • isInstanceOf(Type) → 발생한 예외가 특정 타입인지확인
  • hasMessageContaining(text) → 예외 메시지에 특정 문자열이 포함되었는지 확인

.
.
.

다음 포스팅에서는 Repository Layer 테스트하는 방법과 그 예시에 대해 정리한다.

profile
백엔드 개발자

0개의 댓글