반응형
컨트롤러 테스트
Mocking
- 테스트를 위해 실제 객체를 사용하는 것처럼 테스트를 위해 만든 모형(가짜 객체)를 만들어서 사용하는 것을
Mocking
이라고 한다. 모킹한 객체를 이용하면 의존성을 단절시킬 수 있어 테스트하기 좋다. - Mocking은
@MockMvc
를 주입 받아 사용하며, 같이 사용하는 어노테이션으로는@WebMvcTest
와@AutoConfigureMockMvc
가 있다.
MockMvc
perform()
- 해당 메서드를 사용하면, 브라우저에서 서버에 URL을 요청(GET, POST 등)하듯 컨트롤러를 실행시킬 수 있다. 요청을 통해
MockMvcHttpServletRequestBuilder
객체를 리턴하면서 HTTP 요청 프로토콜에 관련 정보(파라미터, 헤더, 쿠키 등)을 설정할 수 있다. RequestBuilder
객체를 인자로 받는데, 해당 객체는MockMvcRequestBuilder
의 정적 메서드를 이용해서 생성한다. 즉,MockMvcHttpServletRequestBuilder
는MockMvcRequestBuilder
를 다시 리턴하기 때문에 복잡한 체이닝을 구성하여 요청할 수 있다.
andExpect()
perform()
메서드는 결과로ResultAction
객체를 리턴하는 데, 해당 결과를 검증할 수 있도록andExpect()
를 제공한다.andExpect()
는ResultMatcher
객체를 요구하는데MockMvcResultMatchers
에 정의된 정적 메서드를 통해 생성할 수 있다.- status(), view(), model(), andDo() 등의 메서드를 제공한다.
status() : 응답 상태 코드 검증
view() : 뷰 / 리다이렉트 검증
andExpect(view().name("hello")) // 리턴한 뷰가 hello 인지 검증
andExpect(redirectUrl("/index")) // index 화면으로 리다이렉트 했는지 검증
- 다음과 같이 컨트롤러가 리턴하를 뷰를 검증하는 용도로 사용
model() : 모델 정보 검증
- 컨트롤러에 저장한 모델의 정보들을 검증할 경우
MockMvcResultMatchers.model()
메서드를 사용한다. attributeExists(String name
:name
에 해당하는 데이터가Model
에 있는지 검증attribute(String name, Object value)
:name
에 해당하는 데이터가 value 객체인지 검증
andDo() : 요청/응답 전체 메시지 확인
- 실제로 생성된 요청과 응답 메시지를 모두 확인하고 싶은 경우에
perform()
메서드가 리턴하는ResultActions
의andDo(ResultHandler handler)
메서드를 사용한다. andDo(print())
를 통해 콘솔에 요청 / 응답에 관련된 정보를 모두 출력할 수 있다.
@WebMvcTest
- MVC를 위한 테스트로 웹에서 테스트하기 힘든 컨트롤러를 테스트하는 용도로 사용
@SpringBootTest
어노테이션 보다 가볍게 테스트할 수 있다.@Controller
,@ControllerAdvice
,@JsonComponent
,Converter
등 만 스캔하도록 제한
@AutoConfigureMockMvc
@WebMvcTest
와@SpringBootTest
는MockMvc
를 모킹하기 때문에 충돌이 발생하여 같이 사용할 수 없다.
사용 예시
@Test
@DisplayName("관리자는 컨텐츠 생성 시 201 응답을 받는다.")
fun createContentSuccessTest() {
val createCategory = adminCategoryService.createCategory(CreateCategoryDto("카테고리", "카테고리 설명"))
val categoryId = createCategory.id
val createContentDto = objectMapper.writeValueAsString(
CreateContentDto(
"제목",
LocalDateTime.now(),
LocalDateTime.now(),
"https://videoUrl.com",
"https://imgUrl.com",
false
)
)
mockMvc.perform(
post("/admin/categories/$categoryId/contents")
.content(createContentDto)
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().`is`(201))
.andExpect(jsonPath("$..['id']").exists())
.andExpect(jsonPath("$..['categoryId']").exists())
.andExpect(jsonPath("$..['displayStartAt']").exists())
.andExpect(jsonPath("$..['displayEndAt']").exists())
.andExpect(jsonPath("$..['imgUrl']").exists())
.andExpect(jsonPath("$..['videoUrl']").exists())
.andExpect(jsonPath("$..['visible']").exists())
.andDo(print())
}
참고 자료
반응형