[Spring] Junit @WebMvcTest 의 JPA metamodel must not be empty! 에러!

이원찬·2024년 2월 13일
0

Spring

목록 보기
10/13

참고자료

Spring @WebMvcTest with @EnableJpa* annotation

문제 상황

전체 Spring Context 를 로드 해야하는 @SpringBootTest and @AutoConfigureMockMvc 를 사용하지 않고 필요한 Context만 로드하여 빠르게 test코드를 실행 가능한 @WebMvcTest 어노테이션을 이용해 테스트 코드를 작성 하고 있었다

아래 코드에 대한 포스팅은 이곳으로…

[Spring] 레포, 서비스, 컨트롤러 단 단위테스트 작성하기

package qp.official.qp.web.controller;

@WebMvcTest(QuestionController.class)
class QuestionControllerTest {

    @MockBean
    private QuestionCommandService questionCommandService;
    @MockBean
    private QuestionQueryService questionQueryService;

    private final MockMvc mockMvc;
    private final Gson gson;

    @Autowired
    public QuestionControllerTest(
            MockMvc mockMvc,
            Gson gson
    ) {
        this.mockMvc = mockMvc;
        this.gson = gson;
    }

    @Test
    void createQuestion() {
				// 아직 작성도 안했음...
    }
}

그런데 위 코드 작성후 그냥 실행 시켜 봤더니 다음과 같은 에러를 마주 했다.

JPA metamodel must not be empty!

그냥 봐서는 JPA와 WebMvcTest 어노테이션을 같이 사용하기에 나는 에러인줄로만 알았다.

구글링을 갈겨보니

@Enable* 로 시작하는 어노테이션들은 Applicatoin class에 붙히지 말라고 권장하는 모양이다.

밑은 Spring의 Testing 공식 문서이다.

Spring 공식문서

위에서 User Configuration and Slicing 단원을 살펴보자

If you structure your code in a sensible way, your @SpringBootApplication class is used by default as the configuration of your tests.

It then becomes important not to litter the application’s main class with configuration settings that are specific to a particular area of its functionality.

Assume that you are using Spring Data MongoDB, you rely on the auto-configuration for it, and you have enabled auditing. You could define your @SpringBootApplication as follows:

코드를 합리적인 방식으로 구성하면 @SpringBootApplication 클래스가 기본적으로 테스트의 구성으로 사용됩니다.

그러면 애플리케이션의 특정 기능 영역에 특정한 구성 설정으로 애플리케이션의 메인 클래스를 어지럽히지 않는 것이 중요해집니다.

Spring 데이터 몽고DB를 사용하고 있고, 자동 구성에 의존하며, 감사를 활성화했다고 가정해 보겠습니다. 다음과 같이 @SpringBootApplication을 정의할 수 있습니다:

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@SpringBootApplication
@EnableMongoAuditing
public class MyApplication {

    // ...

}

Because this class is the source configuration for the test, any slice test actually tries to enable Mongo auditing, which is definitely not what you want to do. A recommended approach is to move that area-specific configuration to a separate @Configuration class at the same level as your application, as shown in the following example:

이 클래스는 테스트의 소스 구성이기 때문에 모든 슬라이스 테스트는 실제로 Mongo 감사를 활성화하려고 시도하는데, 이는 확실히 원하지 않는 작업입니다. 권장되는 접근 방식은 다음 예시와 같이 해당 영역별 구성을 애플리케이션과 동일한 수준의 별도의 @Configuration 클래스로 이동하는 것입니다:

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;

@Configuration(proxyBeanMethods = false)
@EnableMongoAuditing
public class MyMongoConfiguration {

    // ...

}

위 내용 요약

Applicatoin class 에 붙은 설정 어노테이션 들은 단위 테스트 실행시에 설정되지 않는다…

(위에서 났던 에러는 내가 Application Class에 설정한 @EnableJpaAuditing 어노테이션이 테스트 실행시 설정 되지 않았다는 것!!)

해결방법은 설정 어노테이션을 다른 @Configuration 클래스에 옮겨 적는것!

@Configuration
@EnableJpaAuditing
public class JpaEnversConfiguration {

}

또는 @MockBean(JpaMetamodelMappingContext.class) 어노테이션을 Test class 에 적는것! (비추)

결론

우리가 사용하던 @Enable* 같은 어노테이션들은 Applicatoin class 에 덕지덕지 붙히지 말자…

Spring 가이드 에서는 Application Class 에는 @SpringBootApplication 어노테이션만 붙히도록 하자!!

profile
소통과 기록이 무기(Weapon)인 개발자

0개의 댓글