Controller
를 테스트 하면서 jpa metamodel must not be empty!
라는 에러 메세지를 만났다.
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private UserService userService;
@Test
@DisplayName("회원 가입을 한다.")
void join() throws Exception {
//given
Map<String, String> input = new HashMap<>();
input.put("loginId", "apple123");
input.put("password", "apple123!");
input.put("alias", "아이폰");
//when
ResultActions actual = mockMvc.perform(
post("/api/user/join").contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(input)));
//then
actual.andExpect(status().isOk());
}
}
테스트 코드를 작성 할때 JPA 관련 설정을 건들지는 않아서, 이런 문제가 왜 발생했는지 찾아보았더니, 이전에 Auditing
설정[엔티티의 생성 시점에서 자동으로 LocalDateTime
을 가진 BaseEntity
생성]을 하면서 Application 에 @EnableJpaAuditing
어노테이션을 달아둔 것이 문제였다.
좀 더 자세히 말하자면,Controller
를 테스트 하기 위해 Test 코드 내부에 @WebMvcTest
를 사용했다.
@WebMvcTest를 좀 찾아보았고, 다음과 같은 특징에 대해 알게되었다.
@Controller
, @ControllerAdvice
, @JsonComponent
, Converter/GenericConverter
, Filter
, WebMvcConfigurer
그리고HandlerMethodArgumentResolve
등이 적용@Component
, @Service
, @Repository
는 적용이 안됨.정리하자면 @WebMvcTest
를 사용한다면 @Controller
를 포함한 SpringMVC
레벨의 컴포넌트들이 적용된다. 이때 @Component
, @Service
, @Repository
는 적용이 안된다.
따라서 테스트 실행 시 JPA-Auditing
관련 빈이 등록이 안된 상태로 Application
에 있던 @EnableJpaAuditing
어노테이션이 적용되었고, 이로인해 JPA metamodel must not be empty!
라는 에러를 불러일으켰다.
만약 @SpringBootTest
를 사용해서 전체 컨텍스트를 로드하면서 모든 빈을 주입받으면 에러가 발생하지 않았지만, Controller
만을 테스트하기 위해서 @WebMvcTest
를 사용하였기 때문에, 이런 방식은 올바르지 않다고 생각했다.
그럼 어떻게 해결해야할까?
방법은 두가지가 있다.
Configuration
설정을 별도 분리하여 @EnableJpaAuditing
를 분리한다. JpaMetaModelMappingContext
클래스의 MockBean
을 추가한다.Configuration
설정을 별도 분리한다면, Configuration
파일이 빈으로서 등록되지 않을 것이고 테스트 코드 실행 시 Application
이 JPA와 상관없이 정상 실행하게 된다.
@Configuration
어노테이션 내부에 @Component
가 있기 때문에, @WebMvcTest
는 해당 설정 파일을 빈으로서 등록하지 않는다.
이 방법은 테스트 코드 실행 시 자동으로 JpaMetaModelMappingContext을 빈으로 등록하게 한다.
위와 같이 등록을 하게 되면 Jpa -Auditing 설정에 대한 컨텍스트가 등록되고 테스트 코드가 동작한다.
나는 방법 1을 선택했다.
이유
@WebMvcTest
를 사용하는 곳이면 Auditing 에 관련 없는 Controller
의 테스트에도, 매번 @MockBean(JpaMetamodelMappingcontest.class)
를 적어줘야하기 때문