
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)를 적어줘야하기 때문