1
votes

I am new to testing the spring application, not sure how to test a application profiles defined application.yml in my spring boot app.

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

My first test appears to be passing, but the second tests is failed with multiple errors,

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]

EDIT: application.yml

server:
    port: ${port:8090}

I do understood that application has actually started on port 8090 and my second attempting to run again on the same port, which I don't want.

so how to tell in my tests to just load the application context rather starting the real application.Any ideas are appreciated.

2
WebApplication.main(new String[0]) - the following code doesn't create Spring context. You do call just java class. What functionality do you test? - Anton Novopashin
well, my intention is to test the behaviour, when the application has no command line arguments passed. so i used new String[0].In this case i would like the default profile to pick up. which is picking up fine. But the problem is when i run two tests same time. - Sasi Kathimanda
Use Environment for that. See documentation docs.spring.io/spring/docs/current/javadoc-api/org/…. - Anton Novopashin
If you want to set profile before Spring init application you can use following example - github.com/jhipster/generator-jhipster/blob/master/generators/… and github.com/jhipster/generator-jhipster/blob/master/generators/… - Anton Novopashin

2 Answers

1
votes

The following code will run spring boot embedded container with random port:

@IntegrationTest("server.port:0") 

In order to set Spring active profile in test you can use ActiveProfilesannotation.

@ActiveProfiles("test")

Set spring.profiles.active in application properties or via environment variable using --spring.profiles.active=test.

Spring contains Environment bean. If you want to obtain profiles in your code you can use following code:

@Autowired
Environment environment;

String[] profiles = environment.getActiveProfiles();

The following code WebApplication.main(new String[0]); is incorrect. You do actually run 2 Spring context.

1
votes

The problem hear is that you start by heands the Spring context with the instructionWebApplication.main(....);

The key point hear is that the test class asserts that you have a test context, that will be a Spring context for testing in this stage you don't have the embedded tomcat started for this I can suggest to use @WebIntegrationTest without @WebAppConfiguration.

In your case in the first test method you will have a Spring context for test and then you start another spring contest that start also tomcat to the 8090 port, after this the second test method heredity the test context, but in the test method you restart the context and another tomcat on the same port and in this stage you get the exception.

The @IntegrationTest("server.port:0") don't work because this annotation work on the test context and not on the context that you start on you heands.

The my advice is refactoring the your code in this way:

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

Two test classes that map the you two siute of test, in the first you can test the profile FalconDev1 in isolation from the default and in the second the other profile. in this way you can benefit of the spring abstractions.

I hope tha this can help you