์ฉ์ด ์ ๋ฆฌ
- `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());
}
}
'๐ป Knowledge > ํ ์คํธ์ฝ๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ ๋์ ํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ํ ๊ตฌ์ฒด์ ์กฐ์ธ + ๋์ ์๊ฐ (0) | 2024.12.31 |
---|---|
Test Doubles ์ ๋ฆฌ (0) | 2024.12.27 |
@SpringBootTest vs @DataJpaTest (0) | 2024.12.19 |
Persistence Layer ํ ์คํธ (2) | 2024.12.19 |
๋ ์ด์ด๋ ์ํคํ ์ฒ(Layered Architecture)์ ํ ์คํธ (0) | 2024.12.19 |