Provide other components with random port information @WebIntegrationTest

I played with Spring boot these last days, and I really like the @WebIntegrationTest annotation, which allows you to start Tomcat and automatically deploy the Spring boot application. This makes it possible to run Tomcat on a random port, which is very simple if you are testing webapp. But my business is a little different. The whole source code is available here:

https://github.com/vincent-fuchs/spring-projects

Using Spring Batch, I need to parse an Excel file and write the elements to a REST web service. It works well when I know in advance the URL that the author should use, and I can test the entire stream in a few seconds using Spring Boot by loading the "hollow" @RestController, which receives requests and makes them available for verifying claims.

(Note. I am sure this would be very useful for many people. It will also work if you try to test the Spring integration configuration

This is the package I want to test, not the webService. But to check the output of this batch, I need this "hollow" web service.

@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { //the webservice client that the batch should use (planning for SOAP impl later) RestCustomerWsClient.class, //the "target" web server, with the 'hollow' endpoint listening TargetRESTSystem.class, //the application under test and its config TestSpecificConfiguration.class, CustomerBatchConfiguration.class} ) @WebIntegrationTest("server.port:8080") @IntegrationTest({"spring.batch.job.enabled=false"}) public class CustomerBatchWithRestTest { @Value("${local.server.port}") public int targetWebServerPort; @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Autowired private DummyCustomerController endpoint ; @Autowired private ConfigurableApplicationContext appCtx ; @Autowired private ConfigurableEnvironment env; @Before public void loadDynamicProperty() { EnvironmentTestUtils.addEnvironment(appCtx, "target.port:"+targetWebServerPort); assertThat(env.getProperty("target.port")).isEqualTo(String.valueOf(targetWebServerPort)).as("port for target server is not register correctly in properties"); } @Test public void targetShouldReceiveExpectedCustomer() throws Exception { JobExecution jobExecution = jobLauncherTestUtils.launchJob(); //assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(endpoint.getReceivedCustomers()).hasSize(1); Customer actualCustomer=endpoint.getReceivedCustomers().get(0); assertThat(actualCustomer.getId()).isEqualTo(1); assertThat(actualCustomer.getFirstName()).isEqualTo("Vincent"); assertThat(actualCustomer.getLastName()).isEqualTo("FUCHS"); } } 

Using these annotations, the TargetRESTSystem will be deployed to tomcat on port 8080.

On the package side, the component that writes is configured this way, with a properties file indicating target.port = 8080:

 public class RestCustomerWsClient implements CustomerWsClient { @Value("${target.host}") private String targetHost="undefined"; @Value("${target.port}") private String targetPort="undefined"; @Override public void sendCustomer(Customer customerFromExcel) { RestTemplate restTemplate = new RestTemplate(); restTemplate.postForEntity("http://"+targetHost+":"+targetPort+"/integrate", customerFromExcel, null); System.out.println("sent client integration request"); } } 

As I said, this works well because I defined the port and matched the value between the WebIntegrationTest annotation and the package-side properties file.

But what if I want to make my test more reliable and use a random port, because I don't want it to fail if the 8080 is already in use by another process? I can use this instead:

 @WebIntegrationTest(randomPort=true) 

I tried different things, but no one works due to the order of loading things:

  • @Before method for dynamic value in properties, but I need to update the context after, and Spring won't let me
  • I also tried setting ApplicationContextInitializer / AbstractGenericContextLoader, but at the time they call, Tomcat is not running yet and I don't have a random value yet.

Basically, I will need my test to run Tomcat, maybe deploy my hollow web service in it, give me a random port so that I can add it to the context , and then load my TestSpecificConfiguration / CustomerBatchConfiguration.

Any idea if this is possible? Or is the annotation for WebIntegrationTest really aimed at testing webapps, on which we perform our own HTTP requests as part of the test?

thanks

Vincent

===== EDIT

in the latest version of the code that I committed, I use reflection to set a dynamic port for my component that is already loaded in the Spring context. https://github.com/vincent-fuchs/spring-projects/commit/df7bf3a76fc6109fdacac21d7dd10b045ccd0458

This works, but obviously this is not the best solution. Therefore, if a person has a clean way to do this, it will be great!

+5
source share

All Articles