Of Spring Boot, Pact Provider Tests and Random Ports
In the world of software the devil is oftentimes hiding in the details. Ideas and frameworks look great from a distance (and even from up close), but once you get down into the nitty-gritty details you’ll often notice some minor issue that, while far from invalidating the entire concept, is nonetheless an inconvenience or just plain inelegant and ugly.
Such is the case when employing the Pact Contract Test framework in combination with Spring Boot. All goes swimmingly, until you arrive at the point where you realise that your provider-side contract test (provider tests typically being set up as integration tests) should run on a random port, so as to avoid conflicts on your CI environment. And here the devil will finally show his face: Spring’s server boots up after your test class is instantiated, but the test class needs an instance of Pact’s
HttpTarget, a class which is constructed with (among other data) the test server’s port. Additionally the class is immutable, its
port field is private and final. Short of resorting to reflection there does not seem to anything that can be done to make this combination work.
Fortunately there does exist one edge case that allows the port to be injected in time for Pact to receive it. Spring’s port needs to be injected not directly into a variable in the test class, but using a setter function where the
HttpTarget can be instantiated. All in all the test code needs to look like this to make it work: