春季启动测试:为每个测试加载上下文?

Posted

技术标签:

【中文标题】春季启动测试:为每个测试加载上下文?【英文标题】:Spring boot test: context loaded for every test? 【发布时间】:2018-08-02 10:21:31 【问题描述】:

在我的项目中,我们有一个用于所有测试的超类。这是那个类的签名

@RunWith(SpringRunner.class)
@SpringBootTest(value = "management.port=0", classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("localhost", "test")
@ContextConfiguration(classes = Application.class, SomeConfiguration.class)
@Ignore
public abstract class AIntegrationTest 

Application.class 是我们的主类,而 SomeConfiguration.class 只是用于一些 @Bean 和其他东西,没什么花哨的。

我使用 gradle,并运行我的测试:

./gradlew :my-project:test

我的问题是:

我不确定是否为每个测试初始化​​上下文。但我可以保证上下文被多次初始化。我通过查看日志知道这一点。

由于初始化了多个上下文,因此上下文似乎相互重叠。我知道这一点是因为其中一个症状就是这个异常:

Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [org.springframework.cloud.context.environment.EnvironmentManager@36408d9e] with key 'environmentManager'; nested exception is javax.management.InstanceAlreadyExistsException: RedeemAway:name=environmentManager,type=EnvironmentManager

即使我不关心加载的多个上下文,我的印象是,当测试完成时,下一个测试会在前一个测试终止之前获得一个新的上下文。我这么说是因为上面的异常重叠。

由于所有测试共享同一个 JVM,当某些 bean 注册两次时,就会出现该异常。从这个链接:

Context caching

据说:

ApplicationContext 可以通过以下组合来唯一标识 用于加载它的配置参数。因此, 配置参数的唯一组合用于生成 缓存上下文的键。 TestContext 框架使用 以下配置参数用于构建上下文缓存键

我明白这一点,但我想知道如何才能做到这一点?我的目标是在同一个 JVM 上运行我的所有测试,并在每个测试中重用上下文。

2 月 22 日星期四编辑

我尝试过的事情:

spring.jmx.enabled: 假 spring.jmx.default-domain: 一些值

真正禁用 JMX 应该无济于事,因为异常是来自 Spring Cloud 的 EnvironmentManager。

【问题讨论】:

如果配置相同,则上下文始终在测试之间缓存。配置取决于加载的配置文件、@MockBean(和朋友)、@TestPropertySource 和其他一些东西。如果这是您使用的,那么您每次都会获得一个新的上下文。此外,您的基类很奇怪,您要么使用 @SpringBootTest@ContextConfiguration,但不能同时使用。 SpringBootTest 文档说您可以指定 ContextConfiguration。这来自文档:“可以在运行基于 Spring Boot 的测试的测试类上指定的注释。在常规 Spring TestContext 框架之外提供以下功能:在没有特定 ContextConfiguration(loader=. ..) 已定义。不使用嵌套@Configuration 且未指定显式类时自动搜索SpringBootConfiguration。" 不,它没有这么说。尽管如此,您正在使用此复制配置。 好的。无论如何,SpringBootTest 或 ContextConfiguration 是我从昨天开始尝试的。到昨天我只有SpringBootTest,问题一模一样。 是的,你是对的。问题是我正在调试我不拥有的代码,当你提到 @MockBean 时,我的团队告诉我我们没有使用它。后来我找到了我在下面发布的链接,然后我做了一个 grep 搜索 @MockBean 并意识到我们正在使用它。删除它,一切都开始工作了。将您的评论作为答案,我会投票。毕竟,这就是答案部分的目的。 【参考方案1】:

我找到了问题的答案。这里解释得很好:

https://github.com/spring-projects/spring-boot/issues/7174

基本上,如果你运行一堆测试,一旦其中一个开始,如果它使用注解@MockBean,它将强制 Spring 重新加载上下文。

奖励:如果您的测试使用 org.mockito.Mock,您将看到相同的行为。

【讨论】:

在我的情况下,@Mock 没有重新加载上下文,但@MockBean 是......使用 Spring Boot 2.1.0.RELEASE。

以上是关于春季启动测试:为每个测试加载上下文?的主要内容,如果未能解决你的问题,请参考以下文章

Maven的验证上启动和每个班级停止春季测试运行

如何在@TestFactory 的每个测试中创建不同的 Spring 上下文?

spring boot单元测试spring context重复加载问题

spring 集成测试无法加载上下文“另一个资源已经存在,名称为 dataSource”

跨junit测试类重用spring应用程序上下文

如何在春季启动测试中覆盖 application-test.yml?