Assume I have made a simple client in my application that uses a remote web service that is exposing a RESTful API at some URI /foo/bar/{baz}
. Now I wish to unit test my client that makes calls to this web service.
Ideally, in my tests, I’d like to mock the responses I get from the web service, given a specific request like /foo/bar/123
or /foo/bar/42
. My client assumes the API is actually running somewhere, so I need a local "web service" to start running on http://localhost:9090/foo/bar
for my tests.
I want my unit tests to be self-contained, similar to testing Spring controllers with the Spring MVC Test framework.
Some pseudo-code for a simple client, fetching numbers from the remote API:
// Initialization logic involving setting up mocking of remote API at
// http://localhost:9090/foo/bar
@Autowired
NumberClient numberClient // calls the API at http://localhost:9090/foo/bar
@Test
public void getNumber42() {
onRequest(mockAPI.get("/foo/bar/42")).thenRespond("{ \"number\" : 42 }");
assertEquals(42, numberClient.getNumber(42));
}
// ..
What are my alternatives using Spring?
Here is a basic example on how to mock a Controller class with Mockito:
The Controller class:
Configure the beans:
The
UserCollectionItemDto
is a simple POJO and it represents what the API consumer sends to the server. The UserProfile is the main object used in the service layer (by theUserService
class). This behaviour also implements the DTO pattern.Finally, mockup the expected behaviour:
The idea is to use the pure Controller bean and mockup its members. In this example, we mocked the
UserService.getUsers()
object to contain a user and then validated whether the Controller would return the right number of users.With the same logic you can test the Service and other levels of your application. This example uses the Controller-Service-Repository Pattern as well :)
If you are using rest and leveraging the DTO pattern, then I'd recommend you follow this tutorial.
Best method is to use WireMock. Add the following dependencies:
Define and use the wiremock as shown below
What you are looking for is the support for Client-side REST Tests in the Spring MVC Test Framework.
Assuming your
NumberClient
uses Spring'sRestTemplate
, this aforementioned support is the way to go!Hope this helps,
Sam
If you use Spring RestTemplate you can use MockRestServiceServer. An example can be found here https://objectpartners.com/2013/01/09/rest-client-testing-with-mockrestserviceserver/
You can easily use Mockito to mock a REST API in Spring Boot.
Put a stubbed controller in your test tree:
Your client will need to call the API on localhost when running tests. This could be configured in
src/test/resources/application.properties
. If the test is usingRANDOM_PORT
, your client under test will need to find that value. This is a bit tricky, but the issue is addressed here: Spring Boot - How to get the running portConfigure your test class to use a
WebEnvironment
(a running server) and now your test can use Mockito in the standard way, returningResponseEntity
objects as needed:You can also use this for end-to-end testing of your entire microservice in an environment with the mock created above. One way to do this is to inject
TestRestTemplate
into your test class, and use that to call your REST API in place ofclientFunctionUnderTest
from the example.How this works
Because
OtherApiHooks
is a@RestController
in the test tree, Spring Boot will automatically establish the specified REST service when running theSpringBootTest.WebEnvironment
.Mockito is used here to mock the controller class -- not the service as a whole. Therefore, there will be some server-side processing managed by Spring Boot before the mock is hit. This may include such things as deserializing (and validating) the path UUID shown in the example.
From what I can tell, this approach is robust for parallel test runs with IntelliJ and Maven.