Spring 启动测试应用程序 Yaml java.lang.IllegalStateException:Tomcat 连接器处于失败状态

Spring Boot Testing Application Yaml java.lang.IllegalStateException: Tomcat connector in failed state

我是测试 spring 应用程序的新手,不确定如何测试在我的 spring 启动中定义 application.yml 的应用程序配置文件应用

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {WebApplication.class})
@WebAppConfiguration

public class ApplicationSettingsTest {
    @Test
    public void applicationPicksRightTeamProfile() throws Exception {
        WebApplication.main(new String[] { "--spring.profiles.active=FalconDev1" });
        String output = this.outputCapture.toString();
        assertThat(output, containsString("falcondev.io"));
    }

    @Test
    public void applicationPicksRightDefaultProfile() throws Exception {
        WebApplication.main(new String[0]);
        String output = this.outputCapture.toString();
        assertThat(output, containsString("defaultdev.io"));
    }
}

我的第一个测试似乎通过了,但第二个测试因多个错误而失败,

org.apache.catalina.LifecycleException: Failed to start component [Connector[org.apache.coyote.http11.Http11NioProtocol-8090]]

Caused by: org.apache.catalina.LifecycleException: service.getName(): "Tomcat"; Protocol handler start failed at org.apache.catalina.connector.Connector.startInternal(Connector.java:1014) ~[tomcat-embed-core-7.0.59.jar:7.0.59]

Caused by: java.net.BindException: Address already in use at sun.nio.ch.Net.bind(Native Method) ~[na:1.6.0_65] org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat servlet container at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:165) Caused by: java.lang.IllegalStateException: Tomcat connector in failed state at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.start(TomcatEmbeddedServletContainer.java:159) ~[spring-boot-1.3.2.RELEASE.jar:1.3.2.RELEASE]

编辑: application.yml

server:
    port: ${port:8090}

我知道应用程序实际上已经在端口 8090 上启动,我第二次尝试在同一端口上再次 运行,但我不希望这样。

因此,如何在我的测试中告诉我们只加载应用程序上下文而不是启动真正的 application.Any 想法值得赞赏。

以下代码将 运行 spring 使用随机端口启动嵌入式容器:

@IntegrationTest("server.port:0") 

为了在测试中设置 Spring 活动配置文件,您可以使用 ActiveProfiles 注释。

@ActiveProfiles("test")

在应用程序属性中设置 spring.profiles.active 或使用 --spring.profiles.active=test 通过环境变量。

Spring 包含 Environment 个 bean。如果您想在代码中获取配置文件,可以使用以下代码:

@Autowired
Environment environment;

String[] profiles = environment.getActiveProfiles();

以下代码 WebApplication.main(new String[0]); 不正确。你实际上做 运行 2 Spring 上下文。

听到的问题是您从头开始 Spring 上下文和指令 WebApplication.main(....);

听到的关键点是测试 class 断言你有一个测试上下文,这将是一个 Spring 用于测试的上下文,在这个阶段你没有嵌入 tomcat 为此开始我可以建议使用 @WebIntegrationTest 而不使用 @WebAppConfiguration

在你的情况下,在第一种测试方法中,你将有一个 Spring 测试上下文,然后你开始另一个 spring 比赛,比赛也开始 tomcat 到 8090 端口,在此之后,第二个测试方法继承了测试上下文,但在测试方法中,您重新启动了上下文,并在同一端口上重新启动了另一个 tomcat,在此阶段,您得到了异常。

@IntegrationTest("server.port:0") 不起作用,因为此注释在测试上下文中起作用,而不在您开始的上下文中起作用。

我的建议是以这种方式重构您的代码:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {WebApplication.class})
@WebIntegrationTest(randomPort = true)
@ActiveProfiles("FalconDev1")
public class ApplicationSettingsTest {

    @Test
    public void applicationPicksRightTeamProfile() throws Exception {

        String output = this.outputCapture.toString();
        assertThat(output, containsString("falcondev.io"));
    } 
}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {WebApplication.class})
@WebIntegrationTest(randomPort = true)
public class ApplicationSettingsTest {

    @Test
    public void applicationPicksRightDefaultProfile() throws Exception {
        String output = this.outputCapture.toString();
        assertThat(output, containsString("defaultdev.io"));
    }
}

两个测试 class 映射您的两个测试位置,在第一个中您可以测试与默认配置文件隔离的配置文件 FalconDev1,在第二个中您可以测试另一个配置文件。通过这种方式,您可以从 spring 抽象中受益。

希望对您有所帮助