使用@WebMvcTest 获取“必须存在至少一个 JPA 元模型”
Posted
技术标签:
【中文标题】使用@WebMvcTest 获取“必须存在至少一个 JPA 元模型”【英文标题】:Getting "At least one JPA metamodel must be present" with @WebMvcTest 【发布时间】:2017-05-06 03:11:51 【问题描述】:我对 Spring 还很陌生,正在尝试为 @Controller
做一些基本的集成测试。
@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerIntegrationTests
@Autowired
private MockMvc mvc;
@MockBean
private DemoService demoService;
@Test
public void index_shouldBeSuccessful() throws Exception
mvc.perform(get("/home").accept(MediaType.TEXT_html)).andExpect(status().isOk());
但我得到了
java.lang.IllegalStateException:无法加载 ApplicationContext 原因:org.springframework.beans.factory.BeanCreationException:创建名为“jpaMappingContext”的bean时出错:调用init方法失败;嵌套异常是 java.lang.IllegalArgumentException:必须存在至少一个 JPA 元模型! 原因:java.lang.IllegalArgumentException:必须存在至少一个 JPA 元模型!与大多数发布此错误的人不同,我不想为此使用 JPA。我是否试图错误地使用@WebMvcTest
?我怎样才能找到邀请 JPA 参加这个聚会的 Spring 魔法?
【问题讨论】:
嗨@Brad,你找到解决方案了吗?我的情况完全一样。 @Artegon 不是真的;我玩了各种各样的东西并最终克服了它,但对什么是错误的或修复它没有清楚的了解。贾斯汀的回答看起来很有希望 嗨@Artegon,请问您找到解决方案了吗,我也遇到了同样的情况 【参考方案1】:我遇到了同样的问题。 @WebMvcTest 查找使用 @SpringBootApplication 注释的类(如果找不到,则在应用程序结构的同一目录中或更高的目录中)。您可以阅读其工作原理@@https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests。
如果您使用 @SpringBootApplication 注释的类也有 @EntityScan /@EnableJpaRepositories 会发生此错误。因为你有这些带有 @SpringBootApplication 的注释并且你正在模拟服务(所以实际上没有使用任何 JPA)。我找到了一种解决方法,它可能不是最漂亮的,但对我有用。
将此类放在您的测试目录(根目录)中。 @WebMvcTest 将在您的实际 Application 类之前找到此类。在这个类中你不必添加@EnableJpaRepositories/@EntityScan。
@SpringBootApplication(scanBasePackageClasses =
xxx.service.PackageMarker.class,
xxx.web.PackageMarker.class
)
public class Application
你的测试看起来会一样。
@RunWith(SpringRunner.class)
@WebMvcTest
@WithMockUser
public class ControllerIT
@Autowired
private MockMvc mockMvc;
@MockBean
private Service service;
@Test
public void testName() throws Exception
// when(service.xxx(any(xxx.class))).thenReturn(xxx);
// mockMvc.perform(post("/api/xxx")...
// some assertions
希望这会有所帮助!
【讨论】:
这是一个很好的解决 MVC 测试和 Spring Boot 之间恼人冲突的方法。似乎有必要将空应用程序类命名为与实际应用程序类相同的名称,并将其放在同一个包中(即,您的示例仅在应用程序实际命名为 Application 时才有效)。您可能想在回答中提及这一点。【参考方案2】:从SpringBootApplication
类中删除任何@EnableJpaRepositories
或@EntityScan
,而不是这样做:
package com.tdk;
@SpringBootApplication
@Import(ApplicationConfig.class )
public class TdkApplication
public static void main(String[] args)
SpringApplication.run(TdkApplication.class, args);
并将其放在单独的配置类中:
package com.tdk.config;
@Configuration
@EnableJpaRepositories(basePackages = "com.tdk.repositories")
@EntityScan(basePackages = "com.tdk.domain")
@EnableTransactionManagement
public class ApplicationConfig
这里是测试:
@RunWith(SpringRunner.class)
@WebAppConfiguration
@WebMvcTest
public class MockMvcTests
【讨论】:
这很奇怪,但似乎不起作用。我尝试将@EntityScan
和@EnableJpaRepositories
注释分离到一个单独的配置类中,它位于应用程序类旁边。应用程序本身正确启动。然而,我的测试表明,应用程序上下文无法启动(提问者提到的错误)。在我的情况下,我确实想在实际应用程序中使用 Jpa,但我不想在我的 Controller-Test 中使用它。【参考方案3】:
或者,您可以在测试用例中定义一个自定义配置类,仅包括控制器(加上它的依赖项),以强制 Spring 使用 this 上下文。
请注意,您仍然可以访问 MockMvc
和您的测试用例中的其他优点,如果它带有 WebMvcTest
注释。
@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerIntegrationTests
@Autowired
private MockMvc mvc;
@MockBean
private DemoService demoService;
@Test
public void index_shouldBeSuccessful() throws Exception
mvc.perform(get("/home").accept(MediaType.TEXT_HTML)).andExpect(status().isOk());
@Configuration
@ComponentScan(basePackageClasses = DemoController.class )
public static class TestConf
【讨论】:
这似乎是一个很好的方法。但是,当我尝试它时,我得到另一个错误,因为对同一包中的不同 RestController 的依赖不满意。据我所知,唯一的关系是它们在同一个包中。如果@ComponentScan 只查看正在测试的类,那么不相关的类怎么会出错? @Tim ComponentScan 的 basePackageClasses 属性暗示“此包和所有子包中的所有组件类”。如果您的控制器共享相同的包,您可以使用包含/排除过滤器来细化范围。 或者,您也可以不使用@ComponentScan,而只使用@Configuration 注解,然后在TestConf
内添加@Bean public DemoController demoController() return new DemoController();
。然后它只会配置那个控制器。
@Tim 使用包含/排除方法,您将获得 real bean。在测试配置中,大多数情况下我们希望模拟/覆盖依赖项,同时仍然针对被测的 real 类。【参考方案4】:
如果有人使用 Spring boot 并且不想删除 @EntityScan
和 @EnableJpaRepositories
,您可以从测试类中删除 @WebMvcTest
注释并添加以下内容:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class DemoControllerIntegrationTests
@Autowired
private MockMvc mvc;
//...
您将能够自动连接 MockMvc
并使用它。
【讨论】:
【参考方案5】:将@MockBean(JpaMetamodelMappingContext.class)
添加到DemoControllerIntegrationTests
类的上面:
@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
@MockBean(JpaMetamodelMappingContext.class)
public class DemoControllerIntegrationTests
...
因为您没有在测试中使用数据库,所以 Spring 会抛出此异常。通过模拟 JpaMetamodelMappingContext
类,您将绕过所需的元模型。
【讨论】:
以上是关于使用@WebMvcTest 获取“必须存在至少一个 JPA 元模型”的主要内容,如果未能解决你的问题,请参考以下文章
spring jpa - 必须存在至少一个 JPA 元模型*
SpringBoot 2.0.2 必须存在至少一个 JPA 元模型
“IllegalArgumentException:必须存在至少一个 JPA 元模型” - 尝试将应用程序同时连接到 mongo 和 sql 时
使用 @WebMvcTest 测试中的 ApplicationContext 异常