[Spring] Mockito

thingzoo·2023년 8월 15일
0

Spring

목록 보기
51/54
post-thumbnail

Mock object(가짜 객체)

  • Service 계층의 메서드를 테스트하려면 Service 객체를 생성할 때 생성자로 Repository를 전달해줘야한다.
  • 하지만 전달하려해도 인터페이스들인데 어떻게 전달할까?

  • 바로 가짜 객체(Mock object)를 사용해서 분리할 수 있다.
  • MockRepository
    • 실제 객체와 겉만 같은 객체
      • 동일한 클래스명, 함수명
    • 실제 DB 작업은 하지 않음
      • DB 작업이 이뤄지는 것처럼
      • 테스트를 위해 필요한 결과값을 return
  • 간단히 'mock' 이라고 부른다.

Mockito

Mockito는 Mock 객체를 쉽게 만들 수 있는 방법 제공하는 Java용 오픈 소스 테스트 프레임워크이다.

📌 테스트 코드 작성 공통 준수 사항

  • 보통 테스트를 위한 라이브러리로 JUnit과 AssertJ 조합을 사용하여 테스트를 한다.

AssertJ

풍부한 assertions 세트와 유용한 오류 메시지를 제공하고 테스트 코드 가독성을 향상시키며, IDE내에서 매우 쉽게 사용할 수 있도록 설계된 Java 라이브러리

  • Spring Boot 적용 시 추가되는 아래의 의존성에 기본적으로 포함되어 있다.
    • testImplementation 'org.springframework.boot:spring-boot-starter-test'
  • import 추가
    • import static org.assertj.core.api.Assertions.*;

Given/When/Then 패턴

가장 흔히 쓰이는 Test Code 스타일을 표현하는 방식으로 테스트 코드를 Given(준비)/When(실행)/Then(검증) 세 단계로 나누는 패턴

  • Given : 어떠한 데이터가 주어질 때.
  • When : 어떠한 기능을 실행하면.
  • Then : 어떠한 결과를 기대한다.

인텔리제이에서 테스트를 작성하려는 클래스명 위에 커서를 대고 cmd + shift + t를 누르면 테스트 클래스를 자동 생성해준다.

Mockito를 사용한 단위 테스트 구현 예시

@ExtendWith(MockitoExtension.class) // @Mock 사용 설정
class ProductServiceTest {

    @Mock // 가짜 객체 주입해줌
    ProductRepository productRepository;

    @Mock
    FolderRepository folderRepository;

    @Mock
    ProductFolderRepository productFolderRepository;
    
    @InjectMocks // 매개변수에 가짜 객체를 주입해줌
    ProductService productService;

    @Test
    @DisplayName("관심 상품 희망가 - 최저가 이상으로 변경")
    void test1() {
        // given
        Long productId = 100L;
        int myprice = ProductService.MIN_MY_PRICE + 3_000_000;

        ProductMypriceRequestDto requestMyPriceDto = new ProductMypriceRequestDto();
        requestMyPriceDto.setMyprice(myprice);

        User user = new User();
        ProductRequestDto requestProductDto = new ProductRequestDto(
                "Apple <b>맥북</b> <b>프로</b> 16형 2021년 <b>M1</b> Max 10코어 실버 (MK1H3KH/A) ",
                "https://shopping-phinf.pstatic.net/main_2941337/29413376619.20220705152340.jpg",
                "https://search.shopping.naver.com/gate.nhn?id=29413376619",
                3515000
        );

        Product product = new Product(requestProductDto, user);
        given(productRepository.findById(productId)).willReturn(Optional.of(product));

        // when
        ProductResponseDto result = productService.updateProduct(productId, requestMyPriceDto);

        /*// then
        assertEquals(myprice, result.getMyprice());*/
        
        // then (assertJ ver.)
        assertThat(myprice).isEqualTo(result.getMyprice());
    }

    @Test
    @DisplayName("관심 상품 희망가 - 최저가 미만으로 변경")
    void test2() {
        // given
        Long productId = 200L;
        int myprice = ProductService.MIN_MY_PRICE - 50;

        ProductMypriceRequestDto requestMyPriceDto = new ProductMypriceRequestDto();
        requestMyPriceDto.setMyprice(myprice);

        ProductService productService = new ProductService(productRepository, folderRepository, productFolderRepository);

        /* // when
        Exception exception = assertThrows(IllegalArgumentException.class, () -> {
            productService.updateProduct(productId, requestMyPriceDto);
        });
        
        // then
        assertEquals(
                "유효하지 않은 관심 가격입니다. 최소 " +ProductService.MIN_MY_PRICE + " 원 이상으로 설정해 주세요.",
                exception.getMessage()
        ); */
        
        // when & then (assertJ ver.)
        assertThatThrownBy(() -> productService.updateProduct(productId, requestMyPriceDto))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("유효하지 않은 관심 가격입니다. 최소 " +ProductService.MIN_MY_PRICE + "원 이상으로 설정해주세요.");
    }
}
profile
공부한 내용은 바로바로 기록하자!

0개의 댓글