10. Spring Cloud Contract WireMock
Prev |  | Next

# 10. Spring Cloud Contract WireMock

Modules giving you the possibility to use WireMock with different servers by using the "ambient" server embedded in a Spring Boot application. Check out the samples for more details.

| Important
The Spring Cloud Release Train BOM imports `spring-cloud-contract-dependencies` which in turn has exclusions for the dependencies needed by WireMock. This might lead to a situation that even if you’re not using Spring Cloud Contract then your dependencies will be influenced anyways.

If you have a Spring Boot application that uses Tomcat as an embedded server, for example (the default with `spring-boot-starter-web`), then you can simply add `spring-cloud-contract-wiremock` to your classpath and add `@AutoConfigureWireMock` in order to be able to use Wiremock in your tests. Wiremock runs as a stub server and you can register stub behaviour using a Java API or via static JSON declarations as part of your test. Here’s a simple example:

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    @AutoConfigureWireMock(port = 0)
    public class WiremockForDocsTests {
    	// A service that calls out over HTTP
    	@Autowired private Service service;

    	// Using the WireMock APIs in the normal way:
    	@Test
    	public void contextLoads() throws Exception {
    		// Stubbing WireMock
    		stubFor(get(urlEqualTo("/resource"))
    				.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
    		// We're asserting if WireMock responded properly
    		assertThat(this.service.go()).isEqualTo("Hello World!");
    	}

    }

To start the stub server on a different port use `@AutoConfigureWireMock(port=9999)` (for example), and for a random port use the value 0. The stub server port will be bindable in the test application context as "wiremock.server.port". Using `@AutoConfigureWireMock` adds a bean of type `WiremockConfiguration` to your test application context, where it will be cached in between methods and classes having the same context, just like for normal Spring integration tests.

## 10.1 Registering Stubs Automatically

If you use `@AutoConfigureWireMock` then it will register WireMock JSON stubs from the file system or classpath, by default from `file:src/test/resources/mappings`. You can customize the locations using the `stubs` attribute in the annotation, which can be a resource pattern (ant-style) or a directory, in which case `*/.json` is appended. Example:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureWireMock(stubs="classpath:/stubs")
    public class WiremockImportApplicationTests {

    	@Autowired
    	private Service service;

    	@Test
    	public void contextLoads() throws Exception {
    		assertThat(this.service.go()).isEqualTo("Hello World!");
    	}

    }

| Note
Actually WireMock always loads mappings from `src/test/resources/mappings` as well as the custom locations in the stubs attribute. To change this behaviour you have to also specify a files root as described next.

## 10.2 Using Files to Specify the Stub Bodies

WireMock can read response bodies from files on the classpath or file system. In that case you will see in the JSON DSL that the response has a "bodyFileName" instead of a (literal) "body". The files are resolved relative to a root directory `src/test/resources/__files` by default. To customize this location you can set the `files` attribute in the `@AutoConfigureWireMock` annotation to the location of the parent directory (i.e. the place `__files` is a subdirectory). You can use Spring resource notation to refer to `file:…​` or `classpath:…​` locations (but generic URLs are not supported). A list of values can be given and WireMock will resolve the first file that exists when it needs to find a response body.

| Note
when you configure the `files` root, then it affects the automatic loading of stubs as well (they come from the root location in a subdirectory called "mappings"). The value of `files` has no effect on the stubs loaded explicitly from the `stubs` attribute.

## 10.3 Alternative: Using JUnit Rules

For a more conventional WireMock experience, using JUnit `@Rules` to start and stop the server, just use the `WireMockSpring` convenience class to obtain an `Options` instance:

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    public class WiremockForDocsClassRuleTests {

    	// Start WireMock on some dynamic port
    	// for some reason `dynamicPort()` is not working properly
    	@ClassRule
    	public static WireMockClassRule wiremock = new WireMockClassRule(
    			WireMockSpring.options().dynamicPort());
    	// A service that calls out over HTTP to localhost:${wiremock.port}
    	@Autowired
    	private Service service;

    	// Using the WireMock APIs in the normal way:
    	@Test
    	public void contextLoads() throws Exception {
    		// Stubbing WireMock
    		wiremock.stubFor(get(urlEqualTo("/resource"))
    				.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
    		// We're asserting if WireMock responded properly
    		assertThat(this.service.go()).isEqualTo("Hello World!");
    	}

    }

The use `@ClassRule` means that the server will shut down after all the methods in this class.

## 10.4 Relaxed SSL Validation for Rest Template

WireMock allows you to stub a "secure" server with an "https" URL protocol. If your application wants to contact that stub server in an integration test, then it will find that the SSL certificates are not valid (it’s the usual problem with self-installed certificates). The best option is often to just re-configure the client to use "http", but if that’s not open to you then you can ask Spring to configure an HTTP client that ignores SSL validation errors (just for tests).

To make this work with minimum fuss you need to be using the Spring Boot `RestTemplateBuilder` in your app, e.g.

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
    	return builder.build();
    }

This is because the builder is passed through callbacks to initalize it, so the SSL validation can be set up in the client at that point. This will happen automatically in your test if you are using the `@AutoConfigureWireMock` annotation (or the stub runner). If you are using the JUnit `@Rule` approach you need to add the `@AutoConfigureHttpClient` annotation as well:

    @RunWith(SpringRunner.class)
    @SpringBootTest("app.baseUrl=https://localhost:6443")
    @AutoConfigureHttpClient
    public class WiremockHttpsServerApplicationTests {

    	@ClassRule
    	public static WireMockClassRule wiremock = new WireMockClassRule(
    			WireMockSpring.options().httpsPort(6443));
    ...
    }

If you are using `spring-boot-starter-test` then you will have the Apache HTTP client on the classpath and it will be selected by the `RestTemplateBuilder` and configured to ignore SSL errors. If you are using the default `java.net` client you don’t need the annotation (but it won’t do any harm). There is no support currently for other clients, but it may be added in future releases.

## 10.5 WireMock and Spring MVC Mocks

Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into a Spring `MockRestServiceServer`. Here’s an example:

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.NONE)
    public class WiremockForDocsMockServerApplicationTests {

    	@Autowired
    	private RestTemplate restTemplate;

    	@Autowired
    	private Service service;

    	@Test
    	public void contextLoads() throws Exception {
    		// will read stubs classpath
    		MockRestServiceServer server = WireMockRestServiceServer.with(this.restTemplate)
    				.baseUrl("https://example.org").stubs("classpath:/stubs/resource.json")
    				.build();
    		// We're asserting if WireMock responded properly
    		assertThat(this.service.go()).isEqualTo("Hello World");
    		server.verify();
    	}
    }

The `baseUrl` is prepended to all mock calls, and the `stubs()` method takes a stub path resource pattern as an argument. So in this example the stub defined at `/stubs/resource.json` is loaded into the mock server, so if the `RestTemplate` is asked to visit `https://example.org/` it will get the responses as declared there. More than one stub pattern can be specified, and each one can be a directory (for a recursive list of all ".json"), or a fixed filename (like in the example above) or an ant-style pattern. The JSON format is the normal WireMock format which you can read about in the WireMock website.

Currently we support Tomcat, Jetty and Undertow as Spring Boot embedded servers, and Wiremock itself has "native" support for a particular version of Jetty (currently 9.2). To use the native Jetty you need to add the native wiremock dependencies and exclude the Spring Boot container if there is one.

## 10.6 Generating Stubs using RestDocs

Spring RestDocs can be used to generate documentation (e.g. in asciidoctor format) for an HTTP API with Spring MockMvc or Rest Assured. At the same time as you generate documentation for your API, you can also generate WireMock stubs, by using Spring Cloud Contract WireMock. Just write your normal RestDocs test cases and use `@AutoConfigureRestDocs` to have stubs automatically in the restdocs output directory. For example:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureRestDocs(outputDir = "target/snippets")
    @AutoConfigureMockMvc
    public class ApplicationTests {

    	@Autowired
    	private MockMvc mockMvc;

    	@Test
    	public void contextLoads() throws Exception {
    		mockMvc.perform(get("/resource"))
    				.andExpect(content().string("Hello World"))
    				.andDo(document("resource"));
    	}
    }

From this test will be generated a WireMock stub at "target/snippets/stubs/resource.json". It matches all GET requests to the "/resource" path.

Without any additional configuration this will create a stub with a request matcher for the HTTP method and all headers except "host" and "content-length". To match the request more precisely, for example to match the body of a POST or PUT, we need to explicitly create a request matcher. This will do two things: 1) create a stub that only matches the way you specify, 2) assert that the request in the test case also matches the same conditions.

The main entry point for this is `WireMockRestDocs.verify()` which can be used as a substitute for the `document()` convenience method. For example:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureRestDocs(outputDir = "target/snippets")
    @AutoConfigureMockMvc
    public class ApplicationTests {

    	@Autowired
    	private MockMvc mockMvc;

    	@Test
    	public void contextLoads() throws Exception {
    		mockMvc.perform(post("/resource")
                    .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
    				.andExpect(status().isOk())
    				.andDo(verify().jsonPath("$.id")
                            .stub("resource"));
    	}
    }

So this contract is saying: any valid POST with an "id" field will get back an the same response as in this test. You can chain together calls to `.jsonPath()` to add additional matchers. The JayWay documentation can help you to get up to speed with JSON Path if it is unfamiliar to you.

Instead of the `jsonPath` and `contentType` convenience methods, you can also use the WireMock APIs to verify the request matches the created stub. Example:

    @Test
    public void contextLoads() throws Exception {
    	mockMvc.perform(post("/resource")
                   .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
    			.andExpect(status().isOk())
    			.andDo(verify()
    					.wiremock(WireMock.post(
    						urlPathEquals("/resource"))
    						.withRequestBody(matchingJsonPath("$.id"))
                           .stub("post-resource"));
    }

The WireMock API is rich - you can match headers, query parameters, and request body by regex as well as by json path - so this can useful to create stubs with a wider range of parameters. The above example will generate a stub something like this:

post-resource.json.

    {
      "request" : {
        "url" : "/resource",
        "method" : "POST",
        "bodyPatterns" : [ {
          "matchesJsonPath" : "$.id"
        }]
      },
      "response" : {
        "status" : 200,
        "body" : "Hello World",
        "headers" : {
          "X-Application-Context" : "application:-1",
          "Content-Type" : "text/plain"
        }
      }
    }

| Note
You can use either the `wiremock()` method or the `jsonPath()` and `contentType()` methods to create request matchers, but not both.

On the consumer side, you can make the `resource.json` generated above available on the classpath (by publishing stubs as JARs for example). After that, you can create a stub using WireMock in a number of different ways, including as described above using `@AutoConfigureWireMock(stubs="classpath:resource.json")`.

## 10.7 Generating Contracts using RestDocs

Another thing that can be generated with Spring RestDocs is the Spring Cloud Contract DSL file and documentation. If you combine that with Spring Cloud WireMock then you’re getting both the contracts and stubs.

Why would you want to use this feature? Some people in the community asked questions about situation in which they would like to move to DSL based contract definition but they already have a lot of Spring MVC tests. Using this feature allows you to generate the contract files that you can later modify and move to proper folders so that the plugin picks them up.

| Tip
You might wonder why this functionality is in the WireMock module. Come to think of it, it does make sense since it makes little sense to generate only contracts and not generate the stubs. That’s why we suggest to do both.

Let’s imagine the following test:

    		this.mockMvc.perform(post("/foo")
    					.accept(MediaType.APPLICATION_PDF)
    					.accept(MediaType.APPLICATION_JSON)
    					.contentType(MediaType.APPLICATION_JSON)
    					.content("{\"foo\": 23, \"bar\" : \"baz\" }"))
    				.andExpect(status().isOk())
    				.andExpect(content().string("bar"))
    				// first WireMock
    				.andDo(WireMockRestDocs.verify()
    						.jsonPath("$[?(@.foo >= 20)]")
    						.jsonPath("$[?(@.bar in ['baz','bazz','bazzz'])]")
    						.contentType(MediaType.valueOf("application/json"))
    						.stub("shouldGrantABeerIfOldEnough"))
    				// then Contract DSL documentation
    				.andDo(document("index", SpringCloudContractRestDocs.dslContract()));

This will lead in the creation of the stub as presented in the previous section, contract will get generated and a documentation file too.

The contract will be called `index.groovy` and look more like this.

    import org.springframework.cloud.contract.spec.Contract

    Contract.make {
        request {
            method 'POST'
            url '/foo'
            body('''
                {"foo": 23 }
            ''')
            headers {
                header('''Accept''', '''application/json''')
                header('''Content-Type''', '''application/json''')
            }
        }
        response {
            status 200
            body('''
            bar
            ''')
            headers {
                header('''Content-Type''', '''application/json;charset=UTF-8''')
                header('''Content-Length''', '''3''')
            }
            testMatchers {
                jsonPath('$[?(@.foo >= 20)]', byType())
            }
        }
    }

the generated document (example for Asciidoc) will contain a formatted contract (the location of this file would be `index/dsl-contract.adoc`).

Prev |  | Next
9. Using the Pluggable Architecture | Home | 11. Links