์ปจํธ๋กค๋ฌ์ ์ญํ
ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์์ฒญ์ ๋ฐ์ ์์ฒญ์ ๋ง๋ ์๋น์ค ์ปดํฌ๋ํธ๋ก ์์ฒญ์ ์ ๋ฌํ๊ณ ๊ทธ ๊ฒฐ๊ด๊ฐ์ ๊ฐ๊ณตํ์ฌ ์๋ต; ์น์ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ ๋ชจ๋
ํ ์คํธ ์ฝ๋ ์์ฑ
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final ProductServiceImpl productService;
@GetMapping()
public ResponseEntity<ProductResponseDto> getProduct(Long number) {
ProductResponseDto productResponseDto = productService.getProduct(number);
return ResponseEntity.status(HttpStatus.OK).body(productResponseDto);
}
@PostMapping()
public ResponseEntity<ProductResponseDto> createProduct(@RequestBody ProductDto productDto) {
ProductResponseDto productResponseDto = productService.saveProduct(productDto);
return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(productResponseDto);
}
@PutMapping()
public ResponseEntity<ProductResponseDto> changeProductName(
@RequestBody ChangeProductNameDto changeProductNameDto) throws Exception {
ProductResponseDto productResponseDto = productService.changeProductName(
changeProductNameDto.getNumber(),
changeProductNameDto.getName());
return ResponseEntity.status(HttpStatus.OK).body(productResponseDto);
}
@DeleteMapping()
public ResponseEntity<String> deleteProduct(Long number) throws Exception {
productService.deleteProduct(number);
return ResponseEntity.status(HttpStatus.OK).body("์ ์์ ์ผ๋ก ์ญ์ ๋์์ต๋๋ค.");
}
}
์์ ๊ฐ์ ์ปจํธ๋กค๋ฌ์ ๋ํด ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค๊ณ ๊ฐ์ ํ์ ๋, ProductController๋ ProductService์ ๊ฐ์ฒด๋ฅผ ์์กด์ฑ ์ฃผ์ ๋ฐ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ปจํธ๋กค๋ฌ๋ง ํ ์คํธํ๊ณ ์ถ๋ค๋ฉด ์๋น์ค ๊ฐ์ฒด๋ ์ธ๋ถ ์์ธ์ ํด๋น
→ ๋ ๋ฆฝ์ ์ธ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ํด์ Mock ๊ฐ์ฒด ํ์ฉ
@WebMvcTest(ProductController.class)
class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
ProductServiceImpl productService;
@Test
@DisplayName("MockMvc๋ฅผ ํตํ Product ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ํ
์คํธ")
void getProduct() throws Exception {
given(productService.getProduct(1L)).willReturn(
new ProductResponseDto(1L, "pen", 1000, 2000));
String productId = "1";
mockMvc.perform(
get("/product?number=" + productId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.number").exists())
.andExpect(jsonPath("$.name").exists())
.andExpect(jsonPath("$.price").exists())
.andExpect(jsonPath("$.stock").exists())
.andDo(print());
verify(productService).getProduct(1L);
}
@Test
@DisplayName("Product ๋ฐ์ดํฐ ์์ฑ ํ
์คํธ")
void createProduct() throws Exception {
given(productService.saveProduct(new ProductDto("pen", 5000, 2000)))
.willReturn(new ProductResponseDto(12315L, "pen", 5000, 2000));
ProductDto productDto = ProductDto.builder()
.name("pen")
.price(5000)
.stock(2000)
.build();
Gson gson = new Gson(); //JSON ํ์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์๋ฐ ๊ฐ์ฒด์ JSON ๋ฌธ์์ด ๊ฐ ๋ณํ ์ง์
String content = gson.toJson(productDto);
mockMvc.perform(
post("/product")
.content(content)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.number").exists())
.andExpect(jsonPath("$.name").exists())
.andExpect(jsonPath("$.price").exists())
.andExpect(jsonPath("$.stock").exists())
.andDo(print());
verify(productService).saveProduct(new ProductDto("pen", 5000, 2000));
}
}
@WebMvcTest
์น์์ ์ฌ์ฉ๋๋ ์์ฒญ๊ณผ ์๋ต์ ๋ํ ํ ์คํธ ์ํ(์ฌ๋ผ์ด์ค ํ ์คํธ)
์ต์ ์ผ๋ก ๋์ ํด๋์ค๋ฅผ ์ง์ ํ๋ฉด ํด๋น ํด๋์ค๋ง ๋ก๋, ์ง์ ํ์ง ์์ผ๋ฉด ์ปจํธ๋กค๋ฌ ๊ด๋ จ ๋น ๊ฐ์ฒด ๋ชจ๋ ๋ก๋
@SpringBootTest์ ๋นํด ํ ์คํธ ๋ถ๋ด์ด ์ ์
@MockBean
์ค์ ๋น ๊ฐ์ฒด๊ฐ ์๋ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ์ฃผ์
ํด๋น ์ ๋ ธํ ์ด์ ์ด ์ ์ธ๋ ๊ฐ์ฒด๋ ์ค์ ๊ฐ์ฒด๊ฐ ์๋๋ฏ๋ก ๊ฒฐ๊ณผ ๋ฐํ๊ณผ ๊ฐ์ ์ค์ ํ์๋ฅผ ์ํํ์ง ์์. ๋ฐ๋ผ์ Mockito์ given() ๋ฉ์๋๋ฅผ ํตํด ๋์ ์ ์ ํ์
@Test
ํ ์คํธ ์ฝ๋๊ฐ ํฌํจ๋์ด ์๋ค๊ณ ์ ์ธํ๋ ์ ๋ ธํ ์ด์
@DisplayName
ํ ์คํธ ๋ฉ์๋๋ช ์ด ๋ณต์กํด์ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง ๊ฒฝ์ฐ ํด๋น ์ ๋ ธํ ์ด์ ์ ํตํด ํ ์คํธ์ ๋ํ ํํ ์ ์ ๊ฐ๋ฅ
given()
์ด๋ค ๋ฉ์๋๊ฐ ํธ์ถ๋๊ณ ์ด๋ค ํ๋ผ๋ฏธํฐ๋ฅผ ์ฃผ์ ๋ฐ๋์ง ๊ฐ์
content()
@RequestBody์ ๊ฐ์ ๋๊ฒจ์ฃผ๋ ์ญํ ์ํ
willReturn()
์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํดํ ๊ฒ์ธ์ง ์ ์
perform()
์๋ฒ๋ก URL ์์ฒญ์ ๋ณด๋ด๋ ๊ฒ์ฒ๋ผ ํต์ ํ ์คํธ ์ฝ๋ ์์ฑ
andExpect()
๊ฒฐ๊ด๊ฐ ๊ฒ์ฆ ์ํ ์ญํ
jsonPath().exists()
๋์ถ๋ ๊ฒฐ๊ด๊ฐ์ ๋ํด ๊ฐ ํญ๋ชฉ์ด ์กด์ฌํ๋์ง ๊ฒ์ฆ
andDo()
์์ฒญ๊ณผ ์๋ต์ ์ ์ฒด ๋ด์ฉ ํ์ธ
verify()
์ง์ ๋ ๋ฉ์๋๊ฐ ์คํ๋๋์ง ๊ฒ์ฆ
์ฌ๋ผ์ด์ค ํ ์คํธ
๋จ์ ํ ์คํธ์ ํตํฉ ํ ์คํธ์ ์ค๊ฐ ๊ฐ๋ ์ผ๋ก, ๋ ์ด์ด๋ ์ํคํ ์ฒ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฐ ๋ ์ด์ด๋ณ ํ ์คํธ ์งํ
ํ์์ฑ
๋จ์ ํ ์คํธ์ ๊ฒฝ์ฐ ๋ชจ๋ ์ธ๋ถ ์์ธ์ ์ฐจ๋จํ๊ณ ํ ์คํธ๋ฅผ ์งํํด์ผ ํ์ง๋ง ์ปจํธ๋กค๋ฌ์ ๊ฐ์ด ๊ฐ๋ ์ ์ธ๋ถ์ ๋ง๋ฟ์ ๋ ์ด์ด์ ๊ฒฝ์ฐ ์ธ๋ถ ์์ธ์ ์ฐจ๋จํ๊ณ ํ ์คํธํ๋ฉด ์๋ฏธ๊ฐ ์์.
๋ํ์ ์ธ ์ ๋ ธํ ์ด์
@DataJdbcTest
@DataJpaTest
@DataMongoTest
@DataRedisTest
@JdbcTest
@JooqTest
@JsonTest
@RestClientTest
@WebFluxTest
@WebMvcTest
@WebServiceClientTest