Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving port already in use in a Spring boot test DEFINED PORT

I have a spring boot application that fires up and executes a class that listens to Application Ready event to call an external service to fetch some data and then use that data to push some rules to the classpath for execution. For local testing we have mocked the external service within our application which works fine during the application startup.

The issue is while testing the application by running it with spring boot test annotation and embedded jetty container either on :

  • RANDOM PORT
  • DEFINED PORT

In case of RANDOM PORT, at the application startup, it picks up the url for the mock service from the properties file at a defined port and has no clue where the embedded container is running since it is randomly picked up, hence failing to give response.

In case of DEFINED PORT, for the first test case file it runs successfully, but the moment next file is picked up, it fails saying the port is already in use.

The test cases are partitioned logically in multiple files and need the external service to be called before the container starts to load the rules.

How can I either share the embedded container between test files in case of using defined port or refactor my application code instead to get hold of the random port while starting up during the test case execution.

Any help would be appreciated.

Application Startup code :

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {

@Autowired
private SomeService someService;

@Override
public void onApplicationEvent(ApplicationReadyEvent arg0) {

    try {
        someService.callExternalServiceAndLoadData();
    }
    catch (Execption e) {}
    }
 }

Test Code Annotations: Test1

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")
public class Test1 {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void tc1() throws IOException {.....}

Test Code Annotations: Test2

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")
public class Test2 {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void tc1() throws IOException {.....}
like image 964
ahjashish Avatar asked Feb 15 '17 12:02

ahjashish


People also ask

What is spring boot test port?

Usually, the most straightforward way to configure the HTTP port of a Spring Boot application is by defining the port in the configuration file application. properties or application. yml. Next, let's go through the two scenarios and discuss different ways to get the port programmatically at runtime.

How do I stop a port running in spring boot?

1) On the top right corner of your console, there is a red button, to stop the spring boot application which is already running on this port just click on the red button to terminate. 2) If the red button is not activated you need to right click on the console and select terminate/disconnect all. Hope this helps.

How do you get the spring boot host and port address during run time?

You can get this information via Environment for the port and the host you can obtain by using InternetAddress . Getting the port this way will only work, if a) the port is actually configured explicitly, and b) it is not set to 0 (meaning the servlet container will choose a random port on startup).


2 Answers

If you insist on using the same port on multiple test, you can prevent spring from caching the context for further tests by annotating your testclass with: @DirtiesContext

In your case:

@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource("classpath:test-application.properties")

Here is a quote from Andy Wilkinson from his answer on this discussion

This is working as designed. Spring Framework's test framework will, by default, cache contexts for possible reuse by multiple test classes. You have two tests with different configuration (due to @TestPropertySource) so they will use different application contexts. The context for the first test will be cached and kept open while the second test is running. Both tests are configured to use the same port for Tomcat's connector. As a result, when the second test is run, the context fails to start due to a port clash with the connector from the first test. You have a few options:

  1. Use RANDOM_PORT
  2. Remove @TestPropertySource from Test2 so that the contexts have identical configuration and the context from the first test can be reused for the second test.
  3. Use @DirtiesContext so that the context isn't cached
like image 79
Joel Neukom Avatar answered Sep 18 '22 09:09

Joel Neukom


I ran across the same issue. I know this question is a little old, but this may be of assistance:

Tests that use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) can also inject the actual port into a field by using the @LocalServerPort annotation, as shown in the following example:

Source: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-user-a-random-unassigned-http-port

The code example given is:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests {

    @Autowired
    ServletWebServerApplicationContext server;

    @LocalServerPort
    int port;

    // ...

}
like image 33
cbreezier Avatar answered Sep 22 '22 09:09

cbreezier