Doing integration tests, I’m trying to mock the comportement of my controller with one or multiple MockWebServer but doesn’t found a solution.
I saw the post here saying that a MockWebServer should only be for a single use.
So I tried a way to use it with @BeforeEach and @AfterEach annotations without success.
I tried this:
@SpringBootTest(
classes = {
MyApplication.class,
},
properties = {
"api.url=TEST",
// ... other properties ...
})
@AutoConfigureMockMvc
class MyControllerTest {
private static MockWebServer serverApiA;
private static MockWebServer serverApiB;
private static MockWebServer serverApiC;
private static MockWebServer serverApiD;
// ... Beans and repos declared here ....
@BeforeEach
public void mockHeadersAndStartMockWebServer() throws CustomException, IOException {
doReturn(new HttpHeaders()).when(SomeServiceImplMock).getHeaders();
serverApiA = new MockWebServer();
serverApiA.start();
HttpUrl httpUrlApiA = serverApiA.url("/operation-a/v1");
String urlApiA = httpUrlApiA.url().toString();
System.setProperty("my-project.api.path.url", urlApiA);
}
@AfterEach
void cleanData() throws IOException {
repositoryA.deleteAll();
repositoryB.deleteAll();
repositoryC.deleteAll();
repositoryD.deleteAll();
serverApiA.shutdown();
}
@WithMockUser(value = "somevalue", authorities = "some-authorities")
@Test
void whenCallControllerMethod_withSpecificCase_thenReturnResponseOKAndStatusKO() throws Exception {
// Given
// ... Some code to initialise my test ...
MockResponse mockResponse = getMockResponseApiA(HttpStatus.OK, SomeEnum.VALUE);
// Mock
serverApiA.enqueue(mockResponse);
// When
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("/specific/operation")
.contentType(MediaType.APPLICATION_JSON)
.content(createRequestBody());
MvcResult mvcResult = mockMvc.perform(request)
.andReturn();
// Then
MockHttpServletResponse response = mvcResult.getResponse();
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
}
But I got this Error = java.lang.IllegalArgumentException: [TEST//operation-a/v1] is not a valid HTTP URL.
I also tried the following solutions:
- Using dispatcher instead of enqueue, but I couldn’t specify multiple “System.setProperty”.
- Using @BeforeAll and @AfterAll at first like this:
@BeforeEach
public void mockHeaders(){
doReturn(new HttpHeaders()).when(SomeServiceImplMock).getHeaders();
}
@BeforeAll
public void startMockWebServer() throws CustomException, IOException {
serverApiA = new MockWebServer();
serverApiB = new MockWebServer();
serverApiC = new MockWebServer();
serverApiD = new MockWebServer();
serverApiA.start();
serverApiB.start();
serverApiC.start();
serverApiD.start();
HttpUrl httpUrlApiA = serverApiA.url("/operation-a/v1");
String urlApiA = httpUrlApiA.url().toString();
System.setProperty("my-project.api.pathA.url", urlApiA);
HttpUrl httpUrlApiB = serverApiB.url("/operation-b/v1");
String urlApiB = httpUrlApiB.url().toString();
System.setProperty("my-project.api.pathB.url", urlApiB);
HttpUrl httpUrlApiC = serverApiC.url("/operation-c/v1");
String urlApiC = httpUrlApiC.url().toString();
System.setProperty("my-project.api.pathC.url", urlApiC);
HttpUrl httpUrlApiD = serverApiD.url("/operation-d/v1");
String urlApiD = httpUrlApiD.url().toString();
System.setProperty("my-project.api.pathD.url", urlApiD);
}
@AfterAll
void cleanData() throws IOException {
repositoryA.deleteAll();
repositoryB.deleteAll();
repositoryC.deleteAll();
repositoryD.deleteAll();
serverApiA.shutdown();
serverApiB.shutdown();
serverApiC.shutdown();
serverApiD.shutdown();
}
It does worked, but I had to be very carefull of which test to do first. serverApiA.enqueue() is the same stack as serverApiB, serverApiC and serverApiD.
Results where sometimes randoms, different if I launch them in debug or not.