JSON.REST?

지옥에서 온 듯한 실행 테스트를 @Test 코드로 바꾸어보자

Jungsoomin :) 2020. 12. 16. 00:01

사실, 개인적 공부로 아는 Test 코드 수준은 MockMvcRequestBuilder, Matcher, Handler, AssertJ 정도 쓰는 거여서 마이크로 서비스 단위 테스를 어떻게 돌려야할지 막막하다.

 

그래서 혼자 공부할 때에 컨트롤러 단위테스트는 여러 모듈의 서비스가 나뉘어져 있으면 YARK 나 PostMan 을 가지고 연관된 서비스를 작동시켜서 테스트했는데, Build 사이클에 Test 가 있는데 왜... 내가 단위테스트를 작성안할까.. 라는 생각에 언제나 휩싸였다.

 

단위테스트를 위해 모든 서버를 켜는 이 지옥과도 같은 테스트 방법에서 탈피할 방법은 Mockito 이였다.


  • 일단 다른 서비스를 호출하는 Class 를 Mocking 해야한다. 원하는 결과 값을 얻기위해 메서드와 리턴 값을 모킹해준다.
  • @Before 가 안보여서 @BeforeAll 을 당겨썼다. 하지만 해당 메서드를 static 으로 바꾸거나 클래스에 @TestInstance(Lifecycle.PER_CLASS) 달던지 둘 중 하나 하세요 라는 메시지 보고 넣었다.
  • WebFlux 가 제공하는 WebTestClient 는 정말정말 강력한 메서드로 포진하고 있다는 것을 느꼈다.
  • 보통 Matchers 나 AssertJ, MockMvcRequestBuilder, MockMvcResultMatcher 에서 끌어 당겨올 걸 여기서 다해결하고 있다. 진짜 놀랍다 이거.

 

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ProductCompositeServiceApplicationTest {

    private static final int PRODUCT_ID_OK = 1;
    private static final int PRODUCT_ID_NOT_FOUND = 2;
    private static final int PRODUCT_ID_INVALID = 3;

    // WebFlux Test
    @Autowired
    private WebTestClient webTestClient;
    
    // 빈 모킹
    @MockBean
    private ProductCompositeIntegration integration;

    @BeforeAll
    public void setUp(){

        // 빈 Mocking Configuration
        when(integration.getProduct(PRODUCT_ID_OK))
                .thenReturn(new Product(PRODUCT_ID_OK, "name", 1, "mock-address"));
        when(integration.getRecommendations(PRODUCT_ID_OK))
                .thenReturn(singletonList(new Recommendation(PRODUCT_ID_OK, 1, "author", 1, "content", "mock address")));
        when(integration.getReviews(PRODUCT_ID_OK)).
                thenReturn(singletonList(new Review(PRODUCT_ID_OK, 1, "author", "subject", "content", "mock address")));

        when(integration.getProduct(PRODUCT_ID_NOT_FOUND)).thenThrow(new NotFoundException("NOT FOUND: " + PRODUCT_ID_NOT_FOUND));

        when(integration.getProduct(PRODUCT_ID_INVALID)).thenThrow(new InvalidInputException("INVALID: " + PRODUCT_ID_INVALID));
    }

    @Test
    public void getProductById(){

        webTestClient.get()
                .uri("/product-composite/"+PRODUCT_ID_OK)
                .accept(APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk()
                .expectHeader().contentType(APPLICATION_JSON)
                .expectBody()
                .jsonPath("$.productId").isEqualTo(PRODUCT_ID_OK)
                .jsonPath("$.recommendations.length()").isEqualTo(1)
                .jsonPath("$.reviews.length()").isEqualTo(1);
    }

    @Test
    public void getProductNotFound(){
        webTestClient.get()
                .uri("/product-composite/"+PRODUCT_ID_NOT_FOUND)
                .accept(APPLICATION_JSON)
                .exchange()
                .expectStatus().isNotFound()
                .expectHeader().contentType(APPLICATION_JSON)
                .expectBody()
                .jsonPath("$.path").isEqualTo("/product-composite/" + PRODUCT_ID_NOT_FOUND)
                .jsonPath("$.message").isEqualTo("NOT FOUND: " + PRODUCT_ID_NOT_FOUND);
    }

    @Test
    public void getProductInvalidInput() {

        webTestClient.get()
                .uri("/product-composite/" + PRODUCT_ID_INVALID)
                .accept(APPLICATION_JSON)
                .exchange()
                .expectStatus().isEqualTo(UNPROCESSABLE_ENTITY)
                .expectHeader().contentType(APPLICATION_JSON)
                .expectBody()
                .jsonPath("$.path").isEqualTo("/product-composite/" + PRODUCT_ID_INVALID)
                .jsonPath("$.message").isEqualTo("INVALID: " + PRODUCT_ID_INVALID);
    }

}

'JSON.REST?' 카테고리의 다른 글

MockMvc - JsonTest  (0) 2020.12.09
JSON 데이터 확인을 위한 Json Formatter 확장프로그램  (0) 2020.07.26