我正在尝试测试应用程序在服务注册表中注册时发生的功能。仅当应用程序具有完整的 Web 上下文时才会发生这种情况(即 spring-boot-starter-web 位于类路径上,并且 servlet 未被模拟)。这是通过 spring-cloud-commons 控制的 AbstractAutoServiceRegistration .
简单测试
所有测试应该执行以下操作:
1) Bring up Web App
2) Verify auto-registration w/ service registry event fired
3) Manually force close app
4) Verify auto-deregistratoin occurred
方法一:@SpringBootTest
SpringBootTest
可以轻松创建完整的 Web 上下文,这非常棒。但我无法在测试中关闭应用程序以强制注销
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = MyAutoConfig.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT
)
@EnableAutoConfiguration
public class DiscoverySpringCloudBootMinimalRegistrationTest {
@Test
public void register_deregister {
// Force-close app to trigger dereigster (causes exception)
((ConfigurableApplicationContext) context).close();
verify(registry, times(1)).register(autoRegistrationServiceRecord);
verify(registry, times(1)).deregister(autoRegistrationServiceRecord);
}
context.close()
调用会导致一个很长的错误,基本上是说不要像这样手动关闭上下文。
..... contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]] is not active. This may be due to one of the following reasons: 1) the context was closed programmatically by user code; 2) the context was closed during parallel test execution either according to @DirtiesContext semantics or due to automatic eviction from the ContextCache due to a maximum cache size policy.
方法 2:WebContextRunner
在这种方法中,我避免了@SpringBootTest
并手动配置上下文运行器。这对于调用 context.close()
非常有效,但配置中的 Web 上下文有一个模拟 servlet,并且不会触发自动注册所需的 WebInitializedEvent
。
public class BasicAutoConfigTests {
private WebApplicationContextRunner runner;
@Test
public void register_deregister() {
runner = new WebApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(MyAutoConfig.class));
runner.run((context) -> {
assertThat(context).hasNotFailed();
ServiceRegistry registry = context.getBean(ServiceRegistry.class);
ServiceRecord autoRegistration = context.getBean(MyServiceRecord.class);
context.close();
verify(registry, times(1)).register(autoRegistration);
verify(registry, times(1)).deregister(autoRegistration);
});
}
这几乎可以工作,但会产生一个 MockServletContext
bean,我认为它无法从 spring- 触发必需的
。这种方法如何引导一个真实的、完整的嵌入式 tomcat 服务器?WebServerInitializedEvent
云共享
最佳答案
按照 Spencer 的建议,我使用 Spring 应用程序构建器创建了一个完整的 Web 应用程序。我还在自动配置模块之外执行了此操作 - 在类路径上使用 spring-boot-starter-web
创建了一个名为“集成测试”的新 Maven 子模块。
@Import(MyAutoConfig.class)
@SpringBootApplication
public class MinStarterBasicApp {
@Bean
ServiceRegistry serviceRegistry() {
return mock(ServiceRegistry.class);
}
static ConfigurableApplicationContext setupWebApp(String... profiles){
System.setProperty("spring.main.allow-bean-definition-overriding", "true");
SpringApplication app = new SpringApplicationBuilder(MinStarterBasicApp.class)
.web(WebApplicationType.SERVLET)
.profiles(profiles)
.build();
return app.run();
}
}
其中profiles
允许我按名称传递application.properties文件,如下所示。此外,确保我们手动关闭
每个测试的应用上下文也很重要。
public class StarterBasicAutoconfigTest {
ConfigurableApplicationContext context;
@After
public void teardown() {
if (context != null && context.isRunning())
context.close();
}
@Test
public void sometest() {
context = MinStarterBasicApp.setupWebApp("profile1");
ServiceRegistry registry = context.getBean(ServiceRegistry.class);
context.close();
Mockito.verify(registry, times(1)).register(any());
Mockito.verify(registry, times(1)).deregister(any());
}
关于java - Spring boot如何测试WebServerInitialized事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55463222/