This is a plugin for auto-generating WireMock stubs as part of documenting your REST API with Spring REST Docs.
The basic idea is to use the requests and responses from the integration tests as stubs for testing your client's API contract. The mock templates can be packaged as jar files and be published into your company's artifact repository for this purpose.
This repository consists of four projects
restdocs-wiremock
: The library to extend Spring REST Docs with WireMock stub snippet generation.restdocs-server
: A sample server documenting its REST API (i.e. the Spring REST Docs "notes" example). Besides producing human-readable documentation it will also generate JSON snippets to be used as stubs for WireMock.wiremock-spring-boot-starter
: A spring boot starter which adds aWireMockServer
to your client's ApplicationContext for integration testing. This is optional, but highly recommended when verifying your client contract in a SpringBootTest.restdocs-client
: A sample client using the server API, with integration testing its client contract against the stubs provided via WireMock.
The project is published on jcenter
from bintray
, so firstly, you need to add jcenter
as package
repository for your project.
Then, add restdocs-wiremock as a dependency in test scope. In gradle it would look like this:
dependencies {
testCompile('com.epages:restdocs-wiremock:0.7.5')
}
Spring Boot 1.3.x users: Please make sure you use the current release of Spring REST Docs, which is
1.1.1.RELEASE
as of this writing. The 1.0.x.RELEASE
, included with Spring Boot 1.3 is not compatible with this plugin.
The example below shows how to set Spring REST Docs to this version, when using Spring dependency management.
dependencyManagement.imports {
ext['spring-restdocs.version'] = '1.1.1.RELEASE'
}
When using maven:
<properties>
<spring-restdocs.version>1.1.1.RELEASE</spring-restdocs.version>
</properties>
<dependency>
<groupId>com.epages</groupId>
<artifactId>restdocs-wiremock</artifactId>
<version>0.7.5</version>
<scope>test</scope>
</dependency>
During REST Docs run, snippets like the one below are generated and put into a dedicated jar file, which you can publish into your artifact repository.
Integration into your test code is as simple as adding wiremockJson()
from com.epages.restdocs.WireMockDocumentation
to the document()
calls for Spring REST Docs. For example:
@RunWith(SpringJUnit4ClassRunner.class)
...
class ApiDocumentation {
// ... the usual test setup.
void testGetSingleNote() {
this.mockMvc.perform(get("/notes/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("get-note",
wiremockJson(),
responseFields( ... )
));
}
}
The snippet below is the resulting snippet of a 200 OK
response to /notes/1
, with
the response body as provided by the integration test.
{
"request" : {
"method" : "GET",
"urlPath" : "/notes/1"
},
"response" : {
"status" : 200,
"headers" : {
"Content-Type" : [ "application/hal+json" ],
"Content-Length" : [ "344" ]
},
"body" : "{\n \"title\" : \"REST maturity model\",\n \"body\" : \"http://martinfowler.com/articles/richardsonMaturityModel.html\",\n \"_links\" : {\n \"self\" : {\n \"href\" : \"http://localhost:8080/notes/1\"\n },\n \"note\" : {\n \"href\" : \"http://localhost:8080/notes/1\"\n },\n \"tags\" : {\n \"href\" : \"http://localhost:8080/notes/1/tags\"\n }\n }\n}"
}
}
On the server side you need to collect the WireMock stubs and publish them into an artifact repository. In gradle this can be achieved by a custom jar task.
task wiremockJar(type: Jar) {
description = 'Generates the jar file containing the wiremock stubs for your REST API.'
group = 'Build'
classifier = 'wiremock'
dependsOn project.tasks.test
from (snippetsDir) {
include '**/wiremock-stub.json'
into "wiremock/${project.name}/mappings"
}
}
TODO: Add maven example.
On the client side, add a dependency to the test-runtime to the jar containing the WireMock stubs. After that, the JSON files can be accessed as classpath resources.
testRuntime (group:'com.epages', name:'restdocs-server', version:'0.7.5', classifier:'wiremock', ext:'jar')
Integrating a WireMock server can easily be achieved by including our wiremock-spring-boot-starter
into your project.
It adds a wireMockServer
bean, which you can auto-wire in your test code. By default, we start WireMock on a dynamic port,
and set a wiremock.port
property to the port WireMock is running on. This property can be used to point your clients
to the location of the WireMock
server.
Services based on spring-cloud-netflix
, i.e. using feign
and ribbon
, are auto-configured for you.
To add a dependency via gradle, extend your build.gradle
with the following line:
testCompile('com.epages:wiremock-spring-boot-starter:0.7.5')
When using maven, add the following dependency in test scope.
<dependency>
<groupId>com.epages</groupId>
<artifactId>wiremock-spring-boot-starter</artifactId>
<version>0.7.5</version>
<scope>test</scope>
</dependency>
Here is an excerpt of the sample test from the restdocs-client project to illustrate the usage.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { ClientApplication.class })
@ActiveProfiles("test") // (1)
@WireMockTest(stubPath = "wiremock/restdocs-server") // (2)
public class NoteServiceTest {
@Autowired
private WireMockServer wireMockServer; // (3)
....
}
- Configure your test to point to your WireMock server.
In our example we are using a Spring Expression inside
application-test.properties
to point our noteservice to WireMock:noteservice.baseUri=http://localhost:${wiremock.port}/
- The
@WireMockTest
annotation enables thewireMockServer
bean, which can be accessed from your test's application context. By default, it starts a WireMockServer on a dynamic port, but you could also set it to a fixed port. ThestubPath
property can be used to point to a classpath resource folder that holds your json stubs. - If you want, you can auto-wire the
WireMockServer
instance, and re-configure it, just as described in the official WireMock documentation.
It is possible to read-in a subset of mappings for each test, by repeating the @WireMockTest
annotation on the test method.
The stubPath
is concatenated from the values given on the test class and the test method, just as a @RequestMapping
annotation in Spring would.
In the example given below, the resulting stubPath provided to WireMock is composed as wiremock/myservice/specific-mappings
.
@WireMockTest(stubPath = "wiremock/myservice")
public class MyTest {
@Test
@WireMockTest(stubPath = "specific-mappings")
public void testDifferentMappings() {
....
}
- Publish the current restdocs-wiremock library code into your local maven repository.
./gradlew restdocs-wiremock:build restdocs-wiremock:publishToMavenLocal
- Run the server tests, which uses the WireMock integration into Spring REST Docs.
As a result, there is a
restdocs-server-wiremock
jar file in your maven repository. Mind that this jar only contains a set of json files without explicit dependency on WireMock itself.
./gradlew restdocs-server:build restdocs-server:publishToMavenLocal
- Run the client tests, that expect a specific API from the server. By mocking a server via WireMock the client can be tested in isolation, but would notice a breaking change.
./gradlew restdocs-client:build
This project makes use of the axion-release-plugin and publishing is automated in travis, when a new release is tagged in git.
Locally you should be able to create a new release by running the release
task on gradle. A successful
travis build of this tag should finally end up on bintray.
./gradlew clean build release