Java Spring boot如何测试WebServerInitialized事件

Java Spring boot如何测试WebServerInitialized事件,java,spring-cloud,Java,Spring Cloud,我试图在应用程序向服务注册表注册时测试应用程序的功能。只有当应用程序具有完整的web上下文(即,springbootstarterweb位于类路径上,并且servlet未被模拟)时,才会发生这种情况。这是通过spring cloud commons控制的 简单测试 所有测试应执行以下操作: 1) Bring up Web App 2) Verify auto-registration w/ service registry event fired 3) Manually force close

我试图在应用程序向服务注册表注册时测试应用程序的功能。只有当应用程序具有完整的web上下文(即,
springbootstarterweb
位于类路径上,并且servlet未被模拟)时,才会发生这种情况。这是通过
spring cloud commons
控制的

简单测试 所有测试应执行以下操作:

1) Bring up Web App
2) Verify auto-registration w/ service registry event fired
3) Manually force close app
4) Verify auto-deregistratoin occurred
方法1:@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()
非常有效,但是configures中的web上下文有一个模拟servlet,并且不会触发自动注册所需的
WebInitializeEvent

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 cloud commons
触发必要的
WebServerInitializeEvent
。这种方法如何引导一个真实、完整的嵌入式tomcat服务器?

按照Spencer的建议,我使用spring应用程序生成器创建了一个完整的web应用程序。我在自动配置模块之外也做了这件事——在类路径上创建了一个名为“集成测试”的新maven子模块,它使用
spring boot starter web

@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());
}

这在很大程度上是一个集成测试。在SpringCloud的某些情况下,我们发现最好的方法是
SpringApplication.run()
。您可以在
@SpringBootTest
中执行此操作吗?如果是这样,您将如何构建应用程序注销时的
验证
?例如,你还会调用
app.close()