다음은 일기를 생성하는 Controller에 대한 테스트 코드이다.
@Tag(name = "Diary", description = "일기 API")
@RestController
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@RequestMapping("/diaries")
public class DiaryController {
private final DiaryService diaryService;
private final S3UploadService s3UploadService;
@Operation(summary = "일기 등록")
@PostMapping
public ResponseEntity<ResultResponse> createDiary(@AuthenticationPrincipal UserDetail user,
@RequestPart("file") MultipartFile multipartFile,
@Valid @RequestPart(value="createRequest") DiaryCreateReq createRequest) throws IOException {
String drawingUrl = s3UploadService.saveFile(multipartFile, user.getUsername());
diaryService.createDiary(user, createRequest, drawingUrl);
return ResponseEntity.ok(ResultResponse.of(ResultCode.DIARY_CREATE_SUCCESS));
}
}
@WebMvcTest(DiaryController.class)
@ExtendWith(RestDocumentationExtension.class)
@DisplayName("Diary 컨트롤러의 ")
class DiaryControllerTest extends MockApiTest {
@MockBean
private DiaryService diaryService;
@MockBean
private S3UploadService s3UploadService;
@Test
@WithCustomMockUser
@DisplayName("일기가 등록되는지 확인한다.")
void createDiary() throws Exception {
MockMultipartFile file = new MockMultipartFile(
"file", // 파라미터 이름
"file_name", // 파일 이름
"image/jpeg",// 파일 타입
"test file".getBytes(StandardCharsets.UTF_8) // 파일 내용
);
given(s3UploadService.saveFile(any(), any())).willReturn(String.valueOf(file));
DiaryCreateReq createReq = DiaryControllerFixture.CREATE_REQ;
String jsonByCreateReq = objectMapper.writeValueAsString(createReq);
MockMultipartFile request = new MockMultipartFile(
"createRequest",
"createRequest",
"application/json",
jsonByCreateReq.getBytes(StandardCharsets.UTF_8)
);
String token = "accessToken";
diaryService.createDiary(any(), any(), any());
ResultActions perform =
mockMvc.perform(
multipart("/diaries")
.file(file)
.file(request)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
);
// then
perform.andExpect(status().isOk());
// docs
perform.andDo(print())
.andDo(document("register diary",
getDocumentRequest(),
getDocumentResponse()));
}
}
이런 에러가 발생했다.
@WebMvcTest 같은 경우는 스프링 MVC를 위한 테스트로 컨트롤러와 관련된 애들만 빈으로 등록하고, Service, Repository같은 레이어는 빈으로 등록하지 않아 의존성을 끊습니다.
즉, 스프링 컨텍스트에서 컨트롤러와 관련된 애들만 빈으로 등록하고 테스트를 합니다.
(@WebMvcTest는 빈으로 등록해서 사용하는 통합 테스트의 일종)
DiaryService
와 S3UploadService
를 Bean으로 등록해주지 않은것인다.@Mock
@MockBean
통합 테스트에서 컨테이너가 필요하고, 빈을 등록해야한다면 @MockBean을 통해 등록해주면 되고,
단위 테스트 같이 컨테이너가 필요 없다면 @Mock을 통해 객체를 만들어주면 됩니다.
통합 테스트에서 컨테이너가 필요하다는 무슨의미지?
단위 테스트 같이 컨테이너가 필요 없다면?
[Spring] SpringBoot 테스트 시 @WebMvcTest와 @SpringBootTest의 차이
[Spring] @Mock과 @MockBean의 차이점은 무엇일까?