1. Introduction
Most non-trivial applications, especially in today’s microservices world, will call other services using a REST API to perform a task.
Unit testing parts of your application that call REST APIs can be difficult and error prone when just using JUnit and Mockito.
If you use Spring’s RestTemplate to call REST services, you could inject a mocked instance of it into your subject under test and stub the relevant method:
Java
RestTemplate restTemplate = mock(RestTemplate.class);
TodoList list = new TodoList("1", "To do today");
Mockito
.when(restTemplate.getForObject(
"http://localhost:8080/lists/1",
TodoList.class)
).thenReturn(list);
Kotlin
val restTemplate = mock(RestTemplate::class.java)
val list = TodoList("1", "To do today")
Mockito.
`when`(restTemplate.getForObject(
"http://localhost:8080/lists/1",
TodoList::class.java)
).thenReturn(list)
But to know exactly which RestTemplate method to stub (getForObject?, getForEntity?, exchange?) , you need to dig into the implementation details of your class, which means your test knows more than it really should. We always prefer black box tests as they are more maintainable: if the implementation of the subject under test changes in a way that doesn’t change the behavior, a black box test doesn’t require any changes either.
Since the interface between our application and the external REST API is HTTP, it would actually be a lot easier if we could stub an actual HTTP request/response pair.
2. Enter Wiremock
WireMock is a tool for mocking HTTP responses and although it can run standalone, it also integrates very nicely into unit tests. Wiremock will simply:
- spin up a Jetty server
- respond to HTTP requests that are triggered from your unit test according to stubbed behaviour you define in your unit test
- stop the Jetty server when your unit test has finished
To use it, add the dependency to your pom.xml or build.gradle:
Maven
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.26.3</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
Gradle
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.26.3' {
exclude group: 'asm', module: 'asm'
}
Two things to note here:
- Use the
wiremock-jre8artifact unless you need to be on JDK 7 in which you should use thewiremockone instead: it holds back the Jetty dependency at version9.2.28.v20190418which is the last version to support JDK 7 - The
asmexclusion is to avoid a dependency conflict if another dependency in your project (transitively) depends onasm. Wiremock usesjson-pathwhich usesasmfor some features, but Wiremock doesn’t seem to use any of those features, so it’s safe to exclude theasmdependency.
For JUnit 4, a WireMockRule is available that will automatically start the WireMock server before every test and stop it after, but this has not been ported to a JUnit 5 extension. And it’s really just a few lines of code:
Java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
class MyServiceTest {
private WireMockServer wireMockServer;
@BeforeEach
public void setup() {
wireMockServer = new WireMockServer(WireMockConfiguration
.wireMockConfig()
.dynamicPort());
wireMockServer.start();
}
@AfterEach
public void tearDown() {
wireMockServer.stop();
}
}
Kotlin
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import com.github.tomakehurst.wiremock.WireMockServer
import com.github.tomakehurst.wiremock.core.WireMockConfiguration
internal class MyServiceTest {
private lateinit var wireMockServer: WireMockServer
@BeforeEach
fun setup() {
wireMockServer = WireMockServer(WireMockConfiguration
.wireMockConfig()
.dynamicPort())
wireMockServer.start()
}
@AfterEach
fun tearDown() {
wireMockServer.stop()
}
}
WireMockConfiguration.wireMockConfig().dynamicPort() creates a WireMockConfiguration that indicates the server can listen on any available port. This is convenient as a predefined port hard-coded into your unit test might not always be available, especially on a continuous build server like Jenkins where several tests might be running at the same time. Once the server has started you can get the actual port using wireMockServer.port(), or the entire base URL of the server using wireMockServer.baseUrl().
We recommend using wireMockServer.baseUrl() as it will include the host name or IP of the actual interface WireMock is listening on: we’ve seen cases where instead of using localhost WireMock picked a physical network interface to listen on and tests that had hard-coded "localhost" suddenly failed.
That’s it! We have a web server running in our unit test. Time to add some behavior to it so it can act as a stand-in for the real-life REST API our application calls.
3. Stubbing HTTP responses
Wiremock will let you create stubs for almost anything HTTP can do. The main method here is WireMockServer.stubFor, which will let you stub based on the HTTP method (GET, POST, PUT, etc.), request headers, request body, etc.; Wiremock calls the parameters to which a stub applies the mapping.
Let’s start with a stub for a simple GET mapping.
3.1. Stubbing a GET response
Let’s say you have a UserService that has a getUsers() method that does a GET call to a REST service at <baseUrl>/users, e.g. https://example.com/api/users, which returns the users as a JSON response:
Java
@lombok.Data
public class User {
private final String username;
@JsonCreator
public User(@JsonProperty("username") String username) {
this.username = username;
}
}
@Service
public class UserService {
private String baseUrl;
private RestTemplate restTemplate;
public UserService(
@Value("${userservice.url}") String baseUrl,
RestTemplate restTemplate
) {
this.baseUrl = baseUrl;
this.restTemplate = restTemplate;
}
public List<User> getUsers() {
ResponseEntity<List<User>> responseEntity = restTemplate.exchange(
baseUrl + "/users",
HttpMethod.GET,
null,
new ParameterizedTypeReference<>() { }
);
return responseEntity.getBody();
}
}
Kotlin
class User @JsonCreator constructor(
@JsonProperty("username")
val username: String
)
@Service
class UserService(
@Value("\${userservice.url}") private val baseUrl: String,
private val restTemplate: RestTemplate
) {
fun getUsers(): List<User> {
val responseEntity = restTemplate.exchange(
"$baseUrl/users",
HttpMethod.GET,
null,
object : ParameterizedTypeReference<List<User>>() { })
return responseEntity.body!!
}
}
To test it with a REST service mocked by WireMock, you’ll stub a GET response, using WireMock.get, and then point your UserService to WireMock instead of to the real REST service:
Java
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
public class UserServiceTest {
private UserService userService;
private WireMockServer wireMockServer;
@BeforeEach
public void setup() {
wireMockServer = new WireMockServer(WireMockConfiguration
.wireMockConfig()
.dynamicPort());
wireMockServer.start();
userService = new UserService(
wireMockServer.baseUrl(),
new RestTemplateBuilder().build());
}
@AfterEach
public void tearDown() {
wireMockServer.stop();
}
@Test
public void testGetUsers() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("[\n" +
" { \"username\": \"john\" },\n" +
" { \"username\": \"mary\" }\n" +
"]")
)
);
// When
List<User> users = userService.getUsers();
// Then
assertThat(users, contains(
hasProperty("username", is("john")),
hasProperty("username", is("mary"))
));
}
}
Kotlin
import com.github.tomakehurst.wiremock.client.WireMock.get
import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo
import com.github.tomakehurst.wiremock.client.WireMock.aResponse
class UserServiceTest {
private lateinit var userService: UserService
private lateinit var wireMockServer: WireMockServer
@BeforeEach
fun setup() {
wireMockServer = WireMockServer(WireMockConfiguration
.wireMockConfig()
.dynamicPort())
wireMockServer.start()
userService = UserService(
wireMockServer.baseUrl(),
RestTemplateBuilder().build())
}
@AfterEach
fun tearDown() {
wireMockServer.stop()
}
@Test
fun testGetUsers() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
[
{ "username": "john" },
{ "username": "mary" }
]""".trimIndent())
)
)
// When
val users = userService.getUsers()
// Then
assertThat(users, contains(
hasProperty("username", `is`("john")),
hasProperty("username", `is`("mary"))
))
}
}
3.1.1. Matching on query parameters
If your request has query parameters, you can also match on query parameters by including them in the relative URL you pass to urlEqualTo.
Let’s add a method getUsersByUsername to our UserService which uses a query parameter when calling the REST service:
Java
public List<User> getUsersByName(String username) {
ResponseEntity<List<User>> responseEntity = restTemplate.exchange(
baseUrl + "/users?name={name}",
HttpMethod.GET,
null,
new ParameterizedTypeReference<>() { },
username);
return responseEntity.getBody();
}
Kotlin
fun getUsersByName(username: String): List<User> {
val responseEntity = restTemplate.exchange(
"$baseUrl/users?name={name}",
HttpMethod.GET,
null,
object : ParameterizedTypeReference<List<User>>() { },
username)
return responseEntity.body!!
}
We can test this as follows:
Java
@Test
public void testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users?name=john"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("[\n" +
" { \"username\": \"john\" }\n" +
"]")
)
);
// When
List<User> users = userService.getUsersByName("john");
// Then
assertThat(users, contains(
hasProperty("username", is("john"))
));
}
Kotlin
@Test
fun testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users?name=john"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
[
{ "username": "john" }
]""".trimIndent())
)
)
// When
val users = userService.getUsersByName("john")
// Then
assertThat(users, contains(
hasProperty("username", `is`("john"))
))
}
However, you need to URL encode the query parameters yourself if you do it like this. E.g. if you’re testing your method with a username containing an ampersand (&), you’d need to stub the REST call like this:
Java
@Test
public void testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users?name=john%26mary"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("[\n" +
" { \"username\": \"john&mary\" }\n" +
"]")
)
);
// When
List<User> users = userService.getUsersByName("john&mary");
// Then
assertThat(users, contains(
hasProperty("username", is("john&mary"))
));
}
Kotlin
@Test
fun testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlEqualTo("/users?name=john%26mary"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
[
{ "username": "john&mary" }
]""".trimIndent())
)
)
// When
val users = userService.getUsersByName("john&mary")
// Then
assertThat(users, contains(
hasProperty("username", `is`("john&mary"))
))
}
It’s easier to let WireMock take care of that for you, by using the urlPathEqualTo method instead of urlEqualTo and adding a withQueryParam to it, like this:
Java
@Test
public void testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlPathEqualTo("/users"))
.withQueryParam("name", equalTo("john&mary"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("[\n" +
" { \"username\": \"john&mary\" }\n" +
"]")
)
);
// When
List<User> users = userService.getUsersByName("john&mary");
// Then
assertThat(users, contains(
hasProperty("username", is("john&mary"))
));
}
Kotlin
@Test
fun testGetUsersByName() {
// Given
wireMockServer.stubFor(
get(urlPathEqualTo("/users"))
.withQueryParam("name", equalTo("john&mary"))
.willReturn(
aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("""
[
{ "username": "john&mary" }
]""".trimIndent())
)
)
// When
val users = userService.getUsersByName("john&mary")
// Then
assertThat(users, contains(
hasProperty("username", `is`("john&mary"))
))
}
3.2. Stubbing a POST response
Our UserService should be able to create users, too. So let’s add a method for that:
Java
public String createUser(String username) {
ResponseEntity<Void> responseEntity = restTemplate.exchange(
baseUrl + "/users",
HttpMethod.POST,
new HttpEntity<>(new User(username)),
Void.class);
URI location = responseEntity.getHeaders().getLocation();
int p = location.getPath().lastIndexOf('/');
return location.getPath().substring(p + 1);
}
Kotlin
fun createUser(username: String): String {
val responseEntity = restTemplate.exchange(
"$baseUrl/users",
HttpMethod.POST,
HttpEntity(User(username)),
Void::class.java)
val location = responseEntity.headers.location
val p = location!!.path.lastIndexOf('/')
return location.path.substring(p + 1)
}
Now let’s test it using WireMock!
When stubbing a response that contains a body, you’ll want to include a matcher on the body contents in your stubbing statement. This way you can verify that your code sends the request body you’re expecting. It also means you can create two stubs for the same relative path, which might be necessary depending on what the code you’re testing does.
To create a stub for a POST call, we use the WireMock.post() method. A few things are different here from the GET stub we did in the previous section:
- We’re using
post(urlEqualTo("/users"))instead ofgeturlEqualTo("/users")), as mentioned, to match on aPOSTrequest - We’re including a
withHeaderto verify that the correctContent-Typeheader is being sent, since a request body should always be accompanied by aContent-Typeheader describing what type of data is in the body. - We’re not using
equalToto match on the request body, since it would do an exact String comparison. Instead, we’ll useequalToJsonwhich does a more lenient comparison on JSON equivalence. This means that extra spaces or newlines in places where they are not significant will not break the test, nor will a different order of the fields. This way our test is more robust, without compromizing on correctness. - We’re stubbing our
POSTmethod to return a201 Createdresponse, which is the normal response for a REST call that creates a resource. We’re also including aLocationheader to the created resource; again, this is a REST best practice. The response has no body, so we’re leaving out thewithBodypart here.
Some REST services will return the resource that was created by a POST call as the response body of that POST call. If that is the case, you should include a withBody in the stub. You can then specify the (JSON) representation that the real REST service would be sending back — and you would include a withHeader as will to indicate the content type of the response body, e.g. application/json.
Java
@Test
public void testCreateUser() {
// Given
wireMockServer.stubFor(
post(urlEqualTo("/users"))
.withHeader("Content-Type", equalTo("application/json"))
.withRequestBody(
equalToJson("{ \"username\": \"lucy\" }"))
.willReturn(
aResponse()
.withStatus(201)
.withHeader("Location",
wireMockServer.baseUrl() + "/users/lucy")
)
);
// When
String userId = userService.createUser("lucy");
// Then
assertEquals("lucy", userId);
}
Kotlin
@Test
fun testCreateUser() {
// Given
wireMockServer.stubFor(
post(urlEqualTo("/users"))
.withHeader("Content-Type", equalTo("application/json"))
.withRequestBody(
equalToJson("{ \"username\": \"lucy\" }"))
.willReturn(
aResponse()
.withStatus(201)
.withHeader("Location",
wireMockServer.baseUrl() + "/users/lucy")
)
)
// When
val userId = userService.createUser("lucy")
// Then
assertEquals("lucy", userId)
}
4. Conclusion
WireMock is a great way to test code that does calls to external REST services. We’ve showed some examples of using WireMock to mock a REST service with both GET and POST methods.
Using this examples, you can start writing your own WireMock-based unit tests. We haven’t gone into writing negative test cases (for example, returning an error response from a WireMock stub), or using other HTTP methods like PATCH, DELETE, or OPTIONS. But it shouldn’t be too hard to adapt these examples to do just that!
The code for this blog post can be found on my GitHub: https://github.com/fransflippo/wiremock-examples
Happy WireMocking!

Have you used WireMock in your tests?
Let us know your experiences by leaving a comment!
