Mock/Stub REST API with WireMock for better unit testing

Last Updated on by

Post summary: Examples how to use WireMock to stub (mock also is possible as a term) REST API in order make better unit testing.

The code shown in examples below is available in GitHub java-samples/wiremock repository.

WireMock

WireMock is a simulator for HTTP-based APIs. Some might consider it a service virtualization tool or a mock server. It enables you to stay productive when an API you depend on doesn’t exist or isn’t complete. It supports testing of edge cases and failure modes that the real API won’t reliably produce. And because it’s fast it can reduce your build time from hours down to minutes.

When to use it

One case where WireMock is very helpful is when building a REST API client. Create simple REST API client using Jersey post describes a way to achieve this with Jersey. In most of the cases REST API might not be forced to fail with certain errors, so WireMock is an excellent addition to standard functional tests to verify that client is working correctly in corner cases. Also, it is mandatory for unit testing because it eliminates dependencies to external services. The mock server is extremely fast and under complete control. Another case where WireMock helps is if you need to create API tests, but API is not ready yet or not working. WireMock can be used to stub the service in order to make testing framework and structure. Once the real server is ready tests will just be elaborated and details cleared up.

How to use it

WireMock is used in JUnit as a rule. More info on JUnit rules can be found in Use JUnit rules to debug failed API tests post. There are WireMockClassRule and WireMockRule. The most appropriate is the class rule, there is no need to create a mock server for each and every test, also additional logic is needed for port collision avoidance. In case you use other unit testing framework there is WireMockServer which can be started before tests and stopped afterward. The code given below is used to REST API client from Create simple REST API client using Jersey post. First JUnit class rule is created.

public class JerseyPersonRestClientTest {

	private static final int WIREMOCK_PORT = 9999;

	@ClassRule
	public static final WireMockClassRule WIREMOCK_RULE
		= new WireMockClassRule(WIREMOCK_PORT);

	private JerseyPersonRestClient clientUnderTest;

	@Before
	public void setUp() throws Exception {
		clientUnderTest
			= new JerseyPersonRestClient("http://localhost:" + WIREMOCK_PORT);
	}
}

Port should be free, otherwise there is com.github.tomakehurst.wiremock.common.FatalStartupException: java.lang.RuntimeException: java.net.BindException: Address already in use: bind exception thrown.

Usage is very simple. There are several methods which are important. Method stubFor() is initializing the stub. Method get() notifies that stub is called with HTTP GET request. Method urlMatching() uses regular expression to match which API path is invoked, then willReturn() returns aResponse() withBody(). There are several with() methods which gives a variety of options for testing. Complete test is below:

@Test
public void testGet_WithBody_PersonJson() {
	String personString = "{\"firstName\":\"FN1\",\"lastName\":\"LN1\"}";
	stubFor(get(urlMatching(".*/person/get/.*"))
		.willReturn(aResponse().withBody(personString)));

	Person actual = clientUnderTest.get(1);

	assertEquals("FN1", actual.getFirstName());
	assertEquals("LN1", actual.getLastName());
}

This is the very straightforward case, where the client should work, but when you start to elaborate on with() scenarios you can sometimes catch an issue with the code being tested. See test below is working correctly in a case where API returns HTTP response code 500 – Internal Server Error. The client might need to add some verification on response codes as well:

@Test
public void testGet_WithStatus() {
	String personString = "{\"firstName\":\"FN1\",\"lastName\":\"LN1\"}";
	stubFor(get(GET_URL)
		.willReturn(aResponse()
		.withStatus(500)
		.withBody(personString)));

	Person actual = clientUnderTest.get(1);

	assertEquals("FN1", actual.getFirstName());
	assertEquals("LN1", actual.getLastName());
}

Wiremock stateful behavior

You can configure Wiremock to respond with series of different responses, hence keeping an internal state. This might happen when you want to perform tests with more steps or some end-to-end scenario. On the first request, Wiremock can respond with one response, on the second request it can respond with a totally different response. See more in Wiremock stateful behaviour.

Difference between stub and mock

In Mock JUnit tests with Mockito example post, I’ve shown how to use Mockito to mock given classes and control their behavior in order to control and eliminate dependencies. Mockito is not suitable for this particular case because if you mock JerseyPersonRestClient‘s get() method it will just return an object, there is no testing whatsoever. Stubbing with WireMock on other hand tests all code for invoking the service, getting a response (controlled by you) and deserializing this response from network stream to Java object. It is much more adequate and close to reality testing.

Conclusion

WireMock is a very powerful framework for API stubbing in order to make your test better and it is a must for unit testing some REST API client.

Related Posts

Read more...

Create simple REST API client using Jersey

Last Updated on by

Post summary: Code examples how to create REST API client using Jersey.

In the current post, I will give code examples how to build REST API client using Jersey. The code shown in examples below is available in GitHub java-samples/wiremock repository.

REST API client

REST API client is needed when you want to consume given REST API, either for production usage or for testing this API. In the latter case, the client does not need to be very sophisticated since it is used just for testing the API with Java code. In the current post, I will show how to create REST API client for Persons functionality of Dropwizard Rest Stub described in Build a RESTful stub server with Dropwizard post.

Jersey 2 and Jackson

Jersey is a framework which allows an easier building of RESTful services. It is one of the most used such frameworks nowadays. Jackson is JSON parser for Java. It is also one of the most used ones. The first step is to import libraries you are going to use:

<dependency>
	<groupId>org.glassfish.jersey.core</groupId>
	<artifactId>jersey-client</artifactId>
	<version>2.25.1</version>
</dependency>
<dependency>
	<groupId>org.glassfish.jersey.media</groupId>
	<artifactId>jersey-media-json-jackson</artifactId>
	<version>2.25.1</version>
</dependency>
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.8.7</version>
</dependency>
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-annotations</artifactId>
	<version>2.8.7</version>
</dependency>

Not mandatory but it is good practice to create an interface for this client and then do implementations. The idea is you may have different implementations and switch between them.

import com.automationrhapsody.wiremock.model.Person;

import java.util.List;

public interface PersonRestClient {

	List<Person> getAll();

	Person get(int id);

	String save(Person person);

	String remove();
}

Now you can start with implementation. In given example constructor take the host which also includes port and scheme. Then it creates ClientConfig object with specific properties. The full list is shown in ClientProperties Javadoc. In the example, I set up timeouts only. Next is to create WebTarget object to query different API endpoints. It could not be simpler than that:

import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.filter.LoggingFilter;

public class JerseyPersonRestClient implements PersonRestClient {

	private final WebTarget webTarget;

	public JerseyPersonRestClient(String host) {
		ClientConfig clientConfig = new ClientConfig()
				.property(ClientProperties.READ_TIMEOUT, 30000)
				.property(ClientProperties.CONNECT_TIMEOUT, 5000);

		webTarget = ClientBuilder
				.newClient(clientConfig)
				.register(new LoggingFilter())
				.target(host);
	}
}

Once WebTarget is instantiated it will be used to query all the endpoints. I will show an implementation of one GET and one POST endpoints consumption:

@Override
public List<Person> getAll() {
	Person[] persons = webTarget
		.path(ENDPOINT_GET_ALL)
		.request()
		.get()
		.readEntity(Person[].class);
	return Arrays.stream(persons).collect(Collectors.toList());
}

@Override
public String save(Person person) {
	if (person == null) {
		throw new RuntimeException("Person entity should not be null");
	}
	return webTarget
		.path(ENDPOINT_SAVE)
		.request()
		.post(Entity.json(person))
		.readEntity(String.class);
}

The full code can be seen in GitHub repo: JerseyPersonRestClient full code.

jersey-media-json-jackson

This is the bonding between Jersey and Jackson. It should be used otherwise Jersey’s readEntity(Class var1) method throws:

Exception in thread “main” org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json, type=class …

or

Exception in thread “main” org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/json, type=class …

Client builder

In the code, there is a class called PersonRestClientBuilder. In the current case it does not do many things, but in reality, it might turn out that a lot of configurations or input is provided to build a REST API client instance. This is where such builder becomes very useful:

public class PersonRestClientBuilder {

	private String host;

	public PersonRestClientBuilder setHost(String host) {
		this.host = host;
		return this;
	}

	public PersonRestClient build() {
		return new JerseyPersonRestClient(host);
	}
}

Unit testing

It is common and best practice that each piece of code is covered by unit tests. In Mock JUnit tests with Mockito example post, I’ve described how Mockito can be used. The problem in the current example is if we use Mockito we have to mock readEntity() method to return some response objects. This is way too much mocking and will not do adequate testing, actually, it does not test at all. We want to test that out REST API client successfully communicates over the wire. In order to do proper testing, we need to use a library called WireMock. In Mock/Stub REST API with WireMock for better unit testing post, I will add more details how to use it.

Conclusion

REST API consuming or testing requires building a client. Jersey is a perfect candidate to be used as an underlying framework. WireMock can be used for unit testing the REST API client you have created.

Related Posts

Read more...