2

I have spring boot app and currently all my test are running green if ai run them separately i.e. manually, but when i run the maven package command then all test run in a serial mode i.e. after each other. What happens then is that i get:

"java.net.BindException: Address already in use".

Basically because the test are running in serial they all try to claim the socket 127.0.0.1:8081. And since the the socket is in a TIME_WAIT state the second test is not able to claim that socket. i.e. the output of netstat -apn

netstat -apn |grep -i 8080

tcp   0      0 127.0.0.1:8080          127.0.0.1:33952         TIME_WAIT 
  • Now i have two different profiles configured i.e. Development and Production i.e. see below:

    @Configuration @Profile("Development") public class TomcatEmbededDevelopmentTesting1Profile extends SpringServletContainerInitializer { ... }

    @Configuration @Profile("Production") public class TomcatEmbededProductionProfile extends SpringServletContainerInitializer { .. }

What I am looking after now is a feature to specify which customer TomcatServletContainerInitializer i can run i.e. i would have 5 different one all listening on different ports/sockets. The problem is if I have 5 different TomcatEmbeded configuration classes that are all marked with "@Profile("Development")" then how do i tell junit to execute the one that i need. I have tired using the @SpringApplicationConfiguration , but that does not fly.

@SpringApplicationConfiguration(classes = {
        ...
        TomcatEmbededDevelopmentTesting1Profile.class,
        ...
        } )

then i found an article on the net that explains that there is some magic annotation @IntegrationTest("server.port:0") which is suppose to randomize that port, but that did not worked for me as well. What is the right way to do it in spring? Any hints are greatly appreciated.

here is example of my test:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(listeners={ ServletTestExecutionListener.class,
                                    DependencyInjectionTestExecutionListener.class,
                                    DirtiesContextTestExecutionListener.class,
                                    WithSecurityContextTestExecutionListener.class 
                                    }
        )

@SpringApplicationConfiguration(classes = {
        SecurityWebApplicationInitializerDevelopment.class, 
        SecurityConfigDevelopment.class, 
        TomcatEmbededDevelopmentTesting1Profile.class,
        Internationalization.class, 
        MVCConfigDevelopment.class,
        PersistenceConfigDevelopment.class,
        ServerAuthenticationSuccessHandler.class,
        ServerRedirectAuthenticationSuccessHandler.class,
        LogicServiceRegistryPostProcessor.class
        } )
@WebAppConfiguration
@EnableWebSecurity
@EnableWebSocket
@EnableGlobalMethodSecurity(prePostEnabled = true)
//@IntegrationTest({"server.port=0", "management.port=0"})
@ActiveProfiles("Development")
    public class quickTest extends TestCase {
..
}
Tito
  • 2,234
  • 6
  • 31
  • 65
  • What version of Spring Boot are you using? – Sam Brannen Jun 15 '16 at 11:12
  • Where does `TestCase` come from? If it's from JUnit 3.8, then you should immediately delete `extends TestCase` since you are in fact using JUnit 4.x. – Sam Brannen Jun 15 '16 at 11:13
  • @SamBrannen Sam i am using the spring/boot-starter-parent artifact version 1.3.5.RELEASE. After your comment I have removed the extends TestCase directive, However i still get that bind exception i.e. address already in use. Do you have any other idea what i can try to change? – Tito Jun 23 '16 at 03:18
  • regarding what else to try, did you see my answer? – Sam Brannen Sep 10 '16 at 10:52

1 Answers1

4

For starters, @Enable* annotations are not supported on test classes with Spring Boot 1.3.x. So delete those and move them to actual @Configuration classes.

Secondly, supplying a huge list of classes to @SpringApplicationConfiguration is a worst practice. The best practice is to define a single @Configuration class for your integration tests which uses @Import to include whatever other configuration classes you need.

Third, use @WebIntegrationTest(randomPort = true) instead of @WebAppConfiguration.

Fourth, do not extend TestCase: this is JUnit 4, not JUnit 3.

Fifth, do not include the ServletTestExecutionListener: it is only used for out-of-container integration testing, and what you are doing is in-container integration testing (i.e., in an embedded Tomcat Servlet container).

Sixth, if you need the random port number, simply inject it via @Value("${local.server.port}").

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(
    listeners = WithSecurityContextTestExecutionListener.class,
    mergeMode = MERGE_WITH_DEFAULTS
)
@SpringApplicationConfiguration({
        SecurityWebApplicationInitializerDevelopment.class, 
        SecurityConfigDevelopment.class, 
        TomcatEmbededDevelopmentTesting1Profile.class,
        Internationalization.class, 
        MVCConfigDevelopment.class,
        PersistenceConfigDevelopment.class,
        ServerAuthenticationSuccessHandler.class,
        ServerRedirectAuthenticationSuccessHandler.class,
        LogicServiceRegistryPostProcessor.class
        })
@WebIntegrationTest(randomPort = true)
@ActiveProfiles("Development")
public class QuickTest {

    @Value("${local.server.port}")
    int port;

    // ...
}

So, see if that gets you any further, and read the Spring Boot Reference Manual for further details on Spring Boot's testing support.

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136