Using WireMock for Integration Testing of Spring RestTemplate Services

This article explains how to write integration tests for Spring services that call external APIs by using WireMock to mock HTTP responses, handle dynamic ports, simulate error and timeout scenarios, and adjust exception handling in RestTemplate calls.

FunTester
FunTester
FunTester
Using WireMock for Integration Testing of Spring RestTemplate Services

Whether you follow the traditional testing pyramid or a newer "testing honeycomb" approach, integration tests should be added at some point in the development process, especially when your service calls external APIs. This article shows how to mock those external calls with WireMock.

ChuckNorrisService is a simple Spring @Service that retrieves a fact via

@Service
public class ChuckNorrisService{
  ...
  public ChuckNorrisFact retrieveFact() {
    ResponseEntity<ChuckNorrisFactResponse> response = restTemplate.getForEntity(url, ChuckNorrisFactResponse.class);
    return Optional.ofNullable(response.getBody()).map(ChuckNorrisFactResponse::getFact).orElse(BACKUP_FACT);
  }
  ...
}

A typical unit test mocks RestTemplate to return a successful response, but you also need a test that simulates HTTP error codes (4xx/5xx). The naive test uses a mocked RestTemplate that returns a ResponseEntity with a 503 status, expecting the service to fall back to a backup fact.

In reality, RestTemplate#getForEntity throws a RestClientException (or a subclass such as HttpStatusCodeException) for error responses, so the mocked ResponseEntity is never returned. This discrepancy motivates the use of WireMock.

WireMock to the rescue starts a mock HTTP server that can be programmed to return specific responses. For JUnit 4 you can use a

@ClassRule
public static WireMockRule wireMockRule = new WireMockRule();

which starts and stops the server automatically.

Typical WireMock configuration methods include:

public void configureWireMockForOkResponse(ChuckNorrisFact fact) throws JsonProcessingException {
  ChuckNorrisFactResponse chuckNorrisFactResponse = new ChuckNorrisFactResponse("success", fact);
  stubFor(get(urlEqualTo("/jokes/random"))
      .willReturn(okJson(OBJECT_MAPPER.writeValueAsString(chuckNorrisFactResponse))));
}

and for error responses:

private void configureWireMockForErrorResponse() {
  stubFor(get(urlEqualTo("/jokes/random"))
      .willReturn(serverError()));
}

Because RestTemplate throws exceptions on error status, the service method is updated to catch them:

public ChuckNorrisFact retrieveFact() {
  try {
    ResponseEntity<ChuckNorrisFactResponse> response = restTemplate.getForEntity(url, ChuckNorrisFactResponse.class);
    return Optional.ofNullable(response.getBody()).map(ChuckNorrisFactResponse::getFact).orElse(BACKUP_FACT);
  } catch (HttpStatusCodeException e) {
    return BACKUP_FACT;
  }
}

Dynamic ports are handled by an ApplicationContextInitializer that injects the randomly assigned WireMock port into the Spring context via ${wiremock.port}, allowing tests to run on cloud providers where fixed ports may be unavailable.

Timeout testing is demonstrated by configuring WireMock to delay responses:

private void configureWireMockForSlowResponse() throws JsonProcessingException {
  ChuckNorrisFactResponse chuckNorrisFactResponse = new ChuckNorrisFactResponse("success", new ChuckNorrisFact(1L, ""));
  stubFor(get(urlEqualTo("/jokes/random"))
      .willReturn(
          okJson(OBJECT_MAPPER.writeValueAsString(chuckNorrisFactResponse))
              .withFixedDelay((int) Duration.ofSeconds(10L).toMillis())));
}

When a timeout occurs, RestTemplate throws a ResourceAccessException, so the catch block is broadened to handle RestClientException (the common superclass of both timeout and HTTP status exceptions).

In summary, the article demonstrates the importance of integration testing and shows how WireMock can be used to mock successful, error, and slow responses for Spring services, including handling dynamic ports and proper exception handling.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaspringresttemplateWiremock
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.