Controller를 테스트하기 위해 @WebMvcTest를 사용하였다. 하지만 'JPA metamodel must not be empty' 예외 문구가 발생하며 테스트에 실패하였다.
왜 이런 문제가 발생하는지 공부하며 알게 된 것들이 많아 정리해보려 한다.
Spring Boot에서 MVC 컨트롤러를 테스트하기 위해 사용되는 어노테이션이다.
테스트를 실행하면, 컨트롤러는 필요한 서비스 빈을 주입받지 못하게 되어 NoSuchBeanDefinitionException 또는 UnsatisfiedDependencyException과 같은 예외가 발생합니다. 이는 컨트롤러의 의존성이 충족되지 않아 애플리케이션 컨텍스트를 로드하는 데 실패하기 때문입니다.
@MockBean을 통해 모의 객체를 주입한다.
애플리케이션이나 테스트 설정에 @EnableJpaAuditing 어노테이션이 존재하면, JPA 감사 기능을 활성화한다. 이로 인해 jpaAuditingHandler 빈이 생성되는데, 이 빈은 JPA 메타모델에 의존한다.
하지만 @WebMvcTest 는 기본적으로 웹 계층의 빈들만 로드하기 때문에 JPA 엔티티나 레포지토리 등이 로드되지 않아 메타모델이 비어있게 되어 발생한다.
Caused by: java.lang.IllegalArgumentException: JPA metamodel must not be empty
JPA 메타모델이 비어있으면 안 된다는 것을 의미한다. 즉, JPA 메타모델이 애플리케이션 컨텍스트에 로드되지 않았다는 뜻이다.
여러가지가 있지만 다음과 같이 해결하였다.
package sample.cafekiosk.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
public class CafekioskApplication {
public static void main(String[] args) {
SpringApplication.run(CafekioskApplication.class, args);
}
}
이 파일에서 @EnableJpaAuditing을 제거하고,
package sample.cafekiosk.spring.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing
@Configuration
public class JpaAuditingConfig {
}
파일 따로 생성
@EnableJpaAuditing 어노테이션을 메인 애플리케이션 클래스에서 별도의 설정 클래스로 이동함으로써 예외가 해결된 이유는 테스트 컨텍스트에서 JPA 감사(Auditing)기능의 자동 구성을 피할 수 있기 때문이다.
@WebMvcTest를 통해 테스트를 한다면 웹 관련 빈들만 애플리케이션 컨텍스트에 등록하는 줄 알았는데, 왜 @EnableJpaAuditing 어노테이션이 동작하는지 이해를 못했다.
문제의 원인이 되었던 어노테이션들을 각각 간략하게 정리해보았다. 그래도 왜 @EnableJpaAuditing 어노테이션이 활성되었는지 와닿지는 않았다. 다음의 사실을 알고나서 이해가 되었다.
@SpringBootTest시 에만 @SpringBootApplication을 통해 애플리케이션 컨텍스트를 설정한다고 생각했다. 하지만 @WebMvcTest시에도 메인 애플리케이션을 통해 기본적인 애플리케이션 컨텍스트를 설정하고, 웹 계층 관련 빈들만 등록한다는 사실을 알게되었다. 따라서 메인 애플리케이션을 설정함에 있어서 @EnableJpaAuditing이 있기에 JPA 감사기능이 활성화 되었던것이고, 별도의 파일을 통해 설정을 관리해서 감사기능이 활성화되지 않았고 그에 따른 에러가 발생하지 않은것이다.