sns 프로젝트를 만드는 도중 Post기능을 추가하고 PostController와 PostService를 만들기전에 로그인과 회원가입 기능을 테스트 했던 UserTest를 다시 돌려보았다
그런데 PostService를 빈으로 등록 할 수 없다는 오류가 발생했다.
테스트 코드
@WebMvcTest
class UserRestControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@MockBean
UserService userService;
@Test
@DisplayName("회원가입 성공")
@WithMockUser
void join_success() throws Exception {
UserJoinRequest userJoinRequest = new UserJoinRequest("id","password");
mockMvc.perform(post("/api/v1/users/join")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userJoinRequest)))
.andDo(print())
.andExpect(status().isOk())
;
}
}
UserController에는 분명 PostService를 사용하지 않고 있는데 오류가 나서 너무 당황했다.
분명 로컬로 돌렸을때는 Post에 대한 기능들이 전부 잘 돌아갔기때문에 더 당황스러웠다.
그래서 구글검색을 해보았지만...
빈을 등록하는 어노테이션 @Service, @Repository, @Component 등을 잘 사용했는지에대한 이야기 뿐이였다.
그래서 오류가 나는 포인트를 다시 생각해 보았다.
정상적으로 main을 작동할 때는 오류가 나지 않고 Test코드가 작동할 때만 빈등록이 안되었다고 나오니 Test코드 안에서의 문제라고 생각했다.
그래서 @MocBean으로 PostService를 주입하였는데 테스트 코드가 통과하였다!
@MockBean
PostService postService;
그런데 의문이 생겼다.
UserController에서는 PostService를 사용하지 않는데 왜 PostService를 빈으로 등록해야 하는걸까??
원인은 @WebMvcTest에있었다.
@SpringBootTest 어노테이션을 사용하면 스프링이 관리하는 모든 빈을 등록시켜서 통합 테스트를 진행하기 때문에 무겁다.
하지만 @WebMvcTest는 web 레이어 관련 빈들만 등록하므로 비교적 가볍다.
web레이어 관련 빈들만 등록되므로 Service는 등록되지 않는다.
따라서 가짜로 만들어줄 필요가 있다. → @MockBean 활용
@WebMvcTest(Class명.class)
1. ()에 작성된 클래스만 실제로 로드하여 테스트 진행
2. ()에 매개변수를 지정하지 않으면 @Controller, @RestController, @RestControllerAdvice등 컨트롤러와 연관된 Bean이 모드 업로드 된다!!!!
사용이유
스프링의 모든 Bean을 로드하는 @SpringBootTest대신 컨트롤러 관련 코드만 테스트 할 경우 사용된다.
내가 작성한 코드에서는 @WebMvcTest에 매개변수를 주지 않아서였다...
@WebMvcTest에 UserRestController를 넣어주니 오류가 해결된것을 확인 할 수 있었다!!
@WebMvcTest(UserRestController.class)
class UserRestControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@MockBean
UserService userService;
@Test
@DisplayName("회원가입 성공")
@WithMockUser
void join_success() throws Exception {
UserJoinRequest userJoinRequest = new UserJoinRequest("id","password");
mockMvc.perform(post("/api/v1/users/join")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(userJoinRequest)))
.andDo(print())
.andExpect(status().isOk())
;
}
}