6

I have the following scenario:

@Transactional
@SpringBootTest
@ActiveProfiles("test")
@AutoConfigureMockMvc
@AutoConfigureWireMock(port = 0)
public abstract class IntegrationTest {
}

public class Test1 extends IntegrationTest {
  // Tests that use WireMock
}

@ActiveProfiles("specific-case-test") // This causes another Application Context to be created.
public class Test2 extends IntegrationTest {
  // Tests that use WireMock
}

public class Test3 extends IntegrationTest {
  // Tests that use WireMock
}

Tests run successfully in all these scenarios:

  • Run the tests individually
  • In the order: Test1, Test3, Test2
  • In the order: Test3, Test1, Test2
  • In the order: Test2, Test3, Test1
  • In the order: Test2, Test1, Test3

The last test to run fails in all these scenarios:

  • In the order: Test1, Test2, Test3
  • In the order: Test3, Test2, Test1

I already investigated the problem and it is related to the Spring Application Context and WireMock.

What is going on? Let's consider that the tests run in that order: Test1, Test2, Test3.

When Test1 runs, an Application Context (AC1) is created and a WireMock server (WM1) is set up, let's say, on port 1. Port 1 is set to AC1 (wiremock.server.port) and WM1 is attached to the test thread. All test passes.

When Test2 runs, another Application Context (AC2) is created and a new WireMock server (WM2) is set up, let's say, on port 2. Port 2 is set to AC2 (wiremock.server.port) and WM2 is attached to the test thread, replacing WM1. All test passes.

When Test3 runs, it reuses AC1 and this causes the tests to fail with the message: 404 Not Found: [No response could be served as there are no stub mappings in this WireMock instance.]. The application state is that wiremock.server.port is 1 (comes from AC1) and WM2 is attached to the test thread. Because of that, stubbing happens against WM2, but the application rest calls are going to WM1, which is listening on port 1.

I already tried to clean the Application Context adding @DirtiesContext to Test2, so it would force Spring to load the third AC, but it doesn't work. However, if I add @DirtiesContext to Test1 or @DirtiesContext(classMode = BEFORE_CLASS) to Test3 it works. I don't want this solution because I have other tests and there is no guarantee in which order the tests will run, so if I add it to Test3, then later the execution order will change and another test will fail. I would like a real solution.

Any ideas?

2
  • Does each AC need a separate WireMock instance? If not, could you start a singular WireMock instance and have all ACs point to it?
    – agoff
    Commented Sep 29, 2020 at 15:55
  • No, however, this is how @AutoConfigureWireMock works. It creates a new WM instance for each AC. I could do as you suggest, but then I have to control everything myself, and then there is no point to use the annotation. If I cannot find a solution, this will be the way to go. Commented Sep 30, 2020 at 19:15

2 Answers 2

3

Not sure if you have found a solution to this but here is how I resolved this.

When the spring cached test contexts are reused the wiremock port changes back to that contexts port but seems to miss some step of configuring the WireMock classes default server config. We had to call WireMock.configureFor(port) in a @Before or @BeforeEach method with the port of the currently running context. This meant that when we did stubFor method calls then the right WireMock port was hit and the server got configured with our stubs correctly, make sure you do this configuring before any resets too.

@Autowired
private Environment environment;

private String getWiremockServerPort() {
    // Get the auto configured port property from the current Spring contexts environment
    return environment.getProperty("wiremock.server.port");
}

@BeforeEach
private void configureWireMockPortToMatchEnvironmentContext() {
    int contextEnvironmentPort = Integer.parseInt(getWiremockServerPort());
    configureFor(contextEnvironmentPort);
}
1
  • I just stop using the annotation and implemented my own solution, however, your suggestion does fix the problem. Commented Apr 24, 2021 at 4:57
3

If you are creating Wiremock stubs in this way:

stubFor(post(urlEqualTo(CALLBACK))
        .willReturn(aResponse().withStatus(202))
);

where used static method "stubFor" from com.github.tomakehurst.wiremock.client.Wiremock, you may try to add in your test class an autowired WiremockServer object:

@Autowired
protected WireMockServer wireMockServer;

and then replace your stub creation with:

wireMockServer.stubFor(post(urlEqualTo(CALLBACK))
        .willReturn(aResponse().withStatus(202))
);

where used non-static method from com.github.tomakehurst.wiremock.WireMockServer.

In my case, this solved the problem.

1
  • It depends a bit on how you design your tests, but it might work for many people. Commented Jul 9, 2022 at 22:43

Not the answer you're looking for? Browse other questions tagged or ask your own question.