java - Spring boot如何测试WebServerInitialized事件

标签 java spring-cloud

我正在尝试测试应用程序在服务注册表中注册时发生的功能。仅当应用程序具有完整的 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- 触发必需的 WebServerInitializedEvent云共享。这种方法如何引导一个真实的、完整的嵌入式 tomcat 服务器?

最佳答案

按照 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/

相关文章:

Java 加密日志

java - 无法使用 gmail api 创建草稿

java - 我们如何以编程方式获取 IntelliJ 中方法的调用层次结构

spring - 请求 'OPTIONS/logout'与'POST/logout不匹配

spring-cloud - 如何使用swagger-codegen-maven-plugin生成spring cloud feign客户端

spring - 如何删除 Spring Cloud Config Server 缓存

java - ProGuard 输出不运行

java - 面试题: Create an object oriented design for Sudoku

spring-boot - 在 Spring WebFlux 中实现 Spring Cloud Sleuth 的 TracingWebFillter

java - @Repository接口(interface)的Spring功能bean注册