๐Ÿ’ป Knowledge/ํ…Œ์ŠคํŠธ์ฝ”๋“œ

Presentation Layer ํ…Œ์ŠคํŠธ

ming412 2024. 12. 27. 11:06

์šฉ์–ด ์ •๋ฆฌ

- `MockMvc`: ์‹ค์ œ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์—†์ด๋„ MVC ๋™์ž‘์„ ๋ชจ์˜(mock)ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก Spring์—์„œ ์ œ๊ณตํ•˜๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

- `@WebMvcTest`: @SpringBootTest๊ฐ€ ์ „์ฒด ๋นˆ์„ ๋ชจ๋‘ ๋„์šฐ๋Š” ํ…Œ์ŠคํŠธ ์–ด๋…ธํ…Œ์ด์…˜์ด์—ˆ๋‹ค๋ฉด, @WebMvcTest๋Š” ์ปจํŠธ๋กค๋Ÿฌ ๊ด€๋ จ ๋นˆ๋“ค๋งŒ ๋„์šฐ๋Š” ๊ฐ€๋ฒผ์šด ํ…Œ์ŠคํŠธ ์–ด๋…ธํ…Œ์ด์…˜

- `@MockBean`: Spring ์ปจํ…์ŠคํŠธ์—์„œ ๋นˆ์„ ๋ชจ์˜(mock) ๊ฐ์ฒด๋กœ ๊ต์ฒดํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

 

@Mock vs @MockBean
@Mock: ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋กœ๋”ฉํ•˜์ง€ ์•Š๊ณ ๋„ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ˆœ์ˆ˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ๋ชจ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์ ํ•ฉ (์„œ๋น„์Šค ํ…Œ์ŠคํŠธ)
@MockBean: ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋กœ๋”ฉํ•ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์—์„œ ๋ชจ์˜ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉ (์ปจํŠธ๋กค๋Ÿฌ ํ…Œ์ŠคํŠธ)

 

Controller ํ…Œ์ŠคํŠธ

์•„๋ž˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ๋งจ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„(get ํ…Œ์ŠคํŠธ)์„ ๋ณด๋ฉด, `data` ํ•„๋“œ๋ฅผ ๊ฒ€์ฆํ•  ๋•Œ ๋ฐฐ์—ด ํƒ€์ž…์ธ์ง€ ์—ฌ๋ถ€๋งŒ ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ ์ด์œ ๋Š”, ์œ ๋‹› ํ…Œ์ŠคํŠธ์—์„œ ์ด๋ฏธ `data`์˜ ๋‚ด์šฉ์„ ๊ฒ€์ฆํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์—์„œ๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์ฒด์ ์ธ ๋‚ด์šฉ ๋Œ€์‹  ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋งŒ ๊ฒ€์ฆํ•˜๋„๋ก ํ•œ ๊ฒƒ์ด๋‹ค. 

@WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private ProductService productService;

    @DisplayName("์‹ ๊ทœ ์ƒํ’ˆ์„ ๋“ฑ๋กํ•œ๋‹ค.")
    @Test
    void createProduct() throws Exception {
        // given
        ProductCreateRequest request = ProductCreateRequest.builder()
            .type(ProductType.HANDMADE)
            .sellingStatus(ProductSellingStatus.SELLING)
            .name("์•„๋ฉ”๋ฆฌ์นด๋…ธ")
            .price(4000)
            .build();

        // when // then
        mockMvc.perform(
                post("/api/v1/products/new")
                    .content(objectMapper.writeValueAsString(request))
                    .contentType(MediaType.APPLICATION_JSON)
            )
            .andDo(print())
            .andExpect(status().isOk());
    }
    
    @DisplayName("์‹ ๊ทœ ์ƒํ’ˆ์„ ๋“ฑ๋กํ•  ๋•Œ ์ƒํ’ˆ ํƒ€์ž…์€ ํ•„์ˆ˜๊ฐ’์ด๋‹ค.")
    @Test
    void createProductWithoutType() throws Exception {
        // given
        ProductCreateRequest request = ProductCreateRequest.builder()
            .sellingStatus(ProductSellingStatus.SELLING)
            .name("์•„๋ฉ”๋ฆฌ์นด๋…ธ")
            .price(4000)
            .build();

        // when // then
        mockMvc.perform(
                post("/api/v1/products/new")
                    .content(objectMapper.writeValueAsString(request))
                    .contentType(MediaType.APPLICATION_JSON)
            )
            .andDo(print())
            .andExpect(status().isBadRequest())
            .andExpect(jsonPath("$.code").value("400"))
            .andExpect(jsonPath("$.status").value("BAD_REQUEST"))
            .andExpect(jsonPath("$.message").value("์ƒํ’ˆ ํƒ€์ž…์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."))
            .andExpect(jsonPath("$.data").isEmpty())
        ;
    }
    
    @DisplayName("ํŒ๋งค ์ƒํ’ˆ์„ ์กฐํšŒํ•œ๋‹ค.")
    @Test
    void getSellingProducts() throws Exception {
        // given
        List<ProductResponse> result = List.of();

        when(productService.getSellingProducts()).thenReturn(result);

        // when // then
        mockMvc.perform(
                get("/api/v1/products/selling")
            )
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value("200"))
            .andExpect(jsonPath("$.status").value("OK"))
            .andExpect(jsonPath("$.message").value("OK"))
            .andExpect(jsonPath("$.data").isArray());
    }
}