Giter VIP home page Giter VIP logo

restdocs-wiremock's Introduction

Spring REST Docs WireMock Integration

oss lifecycle Coverage

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.

Details and background information can be read on our ePages Developer Blog.

Contents

This repository consists of two libraries:

  • restdocs-wiremock: The library to extend Spring REST Docs with WireMock stub snippet generation.
  • wiremock-spring-boot-starter: A spring boot starter which adds a WireMockServer to your client's ApplicationContext for integration testing. This is optional, but highly recommended when verifying your client contract in a SpringBootTest.

Versions

There are multiple major versions of the libraries in different branches. The following table provides an overview which "restdocs-wiremock" release branch is to be used for microservices on specific Spring Boot versions.

restdocs-wiremock version Spring Boot version Java version
1.x.x 3.3.x 21
0.x.x 2.7.x 17

How to include restdocs-wiremock into your server project

Dependencies

The project is published on Maven Central, so firstly, you need to add mavenCentral as package repository for your project.

Then, add restdocs-wiremock as a dependency in test scope. As restdocs-wiremock only depends on spring-restdocs-core, you also need to add either spring-restdocs-mockmvc or spring-restdocs-restassured, depending on your test scenario. It is recommended to use the spring-boot gradle plugin to enable dependency management from the Spring IO Platform.

In gradle it would look like this:

dependencies {
  testCompile('com.epages:restdocs-wiremock:1.0.0')
  testCompile('org.springframework.restdocs:spring-restdocs-mockmvc')
}

When using maven:

<dependency>
	<groupId>com.epages</groupId>
	<artifactId>restdocs-wiremock</artifactId>
	<version>1.0.0</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.springframework.restdocs</groupId>
	<artifactId>spring-restdocs-mockmvc</artifactId>
	<scope>test</scope>
</dependency>

Producing snippets

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}"
  }
}

More flexible request matching using urlPathPattern

The above snippet has a shortcoming. WireMock will only match a request if the url matches the complete path, including the id. This is really inflexible. We can do better by using RestDocumentationRequestBuilders to construct the request using a url template, instead of MockMvcRequestBuilders.

@RunWith(SpringJUnit4ClassRunner.class)
//...
class ApiDocumentation {
    // ... the usual test setup.
    void testGetSingleNote() {
        this.mockMvc.perform(RestDocumentationRequestBuilders.get("/notes/{id}", 1)
          .accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andDo(document("get-note",
          wiremockJson(),
          responseFields( ... )
        ));
    }
}

This generates a snippet that uses urlPathPattern instead if urlPath. So WireMock would match a request with any id value.

{
  "request" : {
    "method" : "GET",
    "urlPathPattern" : "/notes/[^/]+"
  },
  "response" : {
    //...
  }
}

Response Templating

WireMock stubs with static responses are too inflexible in many use cases. That is why WireMock offers Response Templating. Response Templating allows us to make our responses more dynamic by using expressions instead of static values.

restdocs-wiremock allows us to use response template expressions:

this.mockMvc.perform(get("/notes/{id}", id))
  .andDo(document("get-note",
    wiremockJson(idFieldReplacedWithPathParameterValue()),
    //..
));

idFieldReplacedWithPathParameterValue() is a convenience method offered by WireMockDocumentation for the common use case to replace the id field in a response with the value of the second path segment.

The following variant would give the same result:

wiremockJson(templatedResponseField("id").replacedWithWireMockTemplateExpression("request.requestLine.pathSegments.[1]"));

We can also address the path parameter by the URI template name.:

wiremockJson(templatedResponseField("id").replacedWithUriTemplateVariableValue("id");)

The resulting stub contains the expression and WireMock will replace the id field with the value of the path segment when serving a response based on this stub.

{
  "request" : {
    "method" : "GET",
    "urlPattern" : "/notes/[^/]+"
  },
  "response" : {
    "transformers" : [ "response-template" ],
    "body" : "{\"id\":\"{{request.requestLine.pathSegments.[1]}}\",\"title\":\"REST maturity model\"}",
    "status" : 200
  }
}

WireMock also offers expressions to generate random values.

wiremockJson(templatedResponseField("id").replacedWithWireMockTemplateExpression("randomValue length=33 type='ALPHANUMERIC'")

Also replacing date values often comes in handy:

wiremockJson(templatedResponseField("date").replacedWithWireMockTemplateExpression("now")

The WireMock stubs jar

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"
	}
}

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:'1.0.0', classifier:'wiremock', ext:'jar')

How to use WireMock in your client tests

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.

Dependencies

To add a dependency via gradle, extend your build.gradle with the following line:

testCompile('com.epages:wiremock-spring-boot-starter:1.0.0')

When using maven, add the following dependency in test scope.

<dependency>
	<groupId>com.epages</groupId>
	<artifactId>wiremock-spring-boot-starter</artifactId>
	<version>1.0.0</version>
	<scope>test</scope>
</dependency>

Important note for Spring Cloud users: The BOM produced by Spring Cloud includes a transitive resolution of WireMock version 1.55, (via spring-cloud-aws -> aws-java-sdk-core -> wiremock (test)). As versions from BOM always override transitive versions coming in through maven dependencies, you need to add an explicit dependency on WireMock 2.x to your project, like shown in the following gradle example:

  testCompile('com.github.tomakehurst:wiremock:2.10.1')

Configuring your test to use the WireMock stubs

Here is an excerpt of the sample test from a 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)

    ....
}
  1. 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}/
  2. The @WireMockTest annotation enables the wireMockServer 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. The stubPath property can be used to point to a classpath resource folder that holds your json stubs.
  3. 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() {
     ....
    }

Building from source

This project uses JDK 21, with source compatibility for Java 21. The JDK can be used via SDKMAN!.

Please execute at least step 1 + 2 if before importing restdocs-wiremock into your IDE.

(1) Publish the current restdocs-wiremock library code into your local maven repository.

./gradlew restdocs-wiremock:build restdocs-wiremock:publishToMavenLocal

(2) 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 local 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

(3) 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

Publishing

Given that the master branch on the upstream repository is in the state from which you want to create a release, execute the following steps:

(1) Create release via the GitHub UI

Use the intended version number as "Tag version".

This will automatically trigger a GitHub Action build which publishes the JAR files for this release to Sonatype.

(2) Login to Sonatype

Login to Sonatype and navigate to the staging repositories.

(3) Close the staging repository

Select the generated staging repository and close it. Check that there are no errors afterwards (e.g. missing signatures or Javadoc JARs).

(4) Release the repository

Select the generated staging repository and publish it. After few minutes, the release should be available in the "Public Repositories" of ePages.

(5) Update documentation

Create a new commit which replaces the previous version number with the new version number in this README file.

Other resources

restdocs-wiremock's People

Contributors

hgslv avatar jensfischer1515 avatar jmewes avatar mduesterhoeft avatar meysamzamani avatar otrosien avatar ozscheyge avatar wodrobina avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restdocs-wiremock's Issues

Stubs loaded from absolute path

We're trying to integrate wiremock-spring-boot-starter in our project using the default configuration (adding dependency + @WireMockTest). We have our response body files under src/test/resources/__files, which is the default location for Wiremock. When we run our tests we get this exception:

java.lang.RuntimeException: java.io.FileNotFoundException: /__files/product-catalog-response.json (No such file or directory)
	at com.github.tomakehurst.wiremock.common.BinaryFile.readContents(BinaryFile.java:38) ~[wiremock-standalone-2.10.1.jar:na]
	at com.github.tomakehurst.wiremock.http.StubResponseRenderer.renderDirectly(StubResponseRenderer.java:95) ~[wiremock-standalone-2.10.1.jar:na]
	at com.github.tomakehurst.wiremock.http.StubResponseRenderer.buildResponse(StubResponseRenderer.java:65) ~[wiremock-standalone-2.10.1.jar:na]
	at com.github.tomakehurst.wiremock.http.StubResponseRenderer.render(StubResponseRenderer.java:54) ~[wiremock-standalone-2.10.1.jar:na]
	at com.github.tomakehurst.wiremock.http.AbstractRequestHandler.handle(AbstractRequestHandler.java:47) ~[wiremock-standalone-2.10.1.jar:na]
	at com.github.tomakehurst.wiremock.servlet.WireMockHandlerDispatchingServlet.service(WireMockHandlerDispatchingServlet.java:102) ~[wiremock-standalone-2.10.1.jar:na]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
	at wiremock.org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812) ~[wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669) ~[wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83) ~[wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:301) ~[wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) ~[wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.Server.handle(Server.java:499) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:258) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) [wiremock-standalone-2.10.1.jar:na]
	at wiremock.org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) [wiremock-standalone-2.10.1.jar:na]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]

It looks like Wiremock is trying to find the files using an absolute path, instead of going to the classpath. In fact, if we create a __files in the root directory of our computer with the same contents the tests work fine.

We haven't been able to figure out how to configure this properly to load the contents from the classpath, is there any way to do it?

Combine efforts with Spring Cloud Contract?

Some work has been done on a slightly different implementation of some of the features in this project at https://github.com/spring-cloud/spring-cloud-contract. (We have talked about it moving into Spring Boot or Spring Test at some point in the future as well.) Would the authors of this library be interested in collaborating over there, and bringing some of the ideas and energy from this project to that one? My email address is easy to find if you want to use a back channel to discuss anything.

Cc @marcingrzejszczak.

Support "WireMock Scenarios" feature

At the moment it is possible to generate wiremock snippets that both document error scenarios and success scenarios for the same URL path. Later on the client the behaviour is non-deterministic on which of these snippets are getting used.

We need a way (like tagging the wiremock snippets) that let's the client specify which of these snippets to use as part of the fixture setup. If that is not possible, either reject or warn when user wants to generate two wiremock snippets of the same URL path.

Downgrade to java7

We should not require java8, and rather align with spring-boot requrements, which is java7.

Support different request matchers

At the moment the path and query params need to match exactly (using WireMock "equalsTo" matcher).
Let's check if there is need for more sophisticated request matching.

Strip down restdocs-server test

At the moment it is a full-blown spring-data-rest test with an embedded h2 database. For demonstration purposes it is sufficient to use spring-hateoas.

Upgrade to wiremock 2.1.12

... and debug why clients are getting wiremock 1.x as dependency resolution. Maybe we need to remove the spring dependency managment plugin from our starter.

bintray upload of wiremock-spring-boot-starter fails

When a release build runs on travis afterwards there is an artifact for restdocs-wiremock but not for wiremock-spring-boot-starter.

After adding info logs for the publish task I see the following exception in the logs:

see https://travis-ci.org/ePages-de/restdocs-wiremock/builds/298611378

FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':wiremock-spring-boot-starter:bintrayUpload'.
> Cannot cast object 'task ':bintrayUpload'' with class 'com.jfrog.bintray.gradle.BintrayUploadTask_Decorated' to class 'com.jfrog.bintray.gradle.BintrayUploadTask'
* Try:
Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output.
* Get more help at https://help.gradle.org
BUILD FAILED in 18s
13 actionable tasks: 7 executed, 6 up-to-date

Executing ./gradlew :wiremock-spring-boot-starter:bintrayUpload locally works fine

Automating parts of publication steps

Calling the Gradle task publishToSonatype creates a new staging repository. This needs to be closed. In the process of closing the repository Sonatype runs a dozen of validations, e.g. that the JAR files are signed and that Javadocs are published. Once this is done, the staging repository needs to be released.

At the moment, it is documented how to do the last two steps manually. They could be automated, if we want to. See publish-plugin/README.md.

Related #74

Not able to resolve 0.7.18

The POM for com.epages:wiremock-spring-boot-starter:pom:0.7.18 is missing, no dependency information available

Problems using restdocs-wiremock alongside feign client

Hello there,

@otrosien @mduesterhoeft @UlfS

Hope this issue finds you in good health.

I'm currently documenting the APIs of Mifos I/O ( https://github.com/mifosio ) which uses a feign client. I got to your restdocs-wiremock integration given that wiremock-spring-boot-starter is said to have worked well for feign clients.

Despite following your example on https://github.com/ePages-de/restdocs-wiremock/server , I am unable to get snippets generated in the build/generated-snippets folder. You can see my build.gradle and ApiDocumentation files here.

Any help from you would be appreciated.

At Your Service,
Isaac Kamga.

IndexOutOfBoundsException for queryParams without value

Bug for URIs that end with an empty queryParam value. For example: http://some.url/?key=

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.get(LinkedList.java:476)
at com.epages.restdocs.WireMockJsonSnippet.queryParams(WireMockJsonSnippet.java:91)
at com.epages.restdocs.WireMockJsonSnippet.createModel(WireMockJsonSnippet.java:71)
at com.epages.restdocs.WireMockJsonSnippet.toJsonString(WireMockJsonSnippet.java:57)
at com.epages.restdocs.WireMockJsonSnippet.document(WireMockJsonSnippet.java:52)

@WireMockTest usually requires @DirtiesContext

Due to the fact that the wiremock test execution listener adds a new property source that is unknown when we started the application context from a different test. So we need to restart the application context, in order to access our wiremock.port property. We need to find a better approach.

Bring project up to date

This project runs on old libraries and technologies.
I would like to motivate to bring it up to date, including

  • update gradle ✔️ #70
    • support Java 11
    • use library and implementation directives instead of compile
  • update dependencies
    • gradle plugins
    • java libraries
    • Spring related
      • multi branch for different versions of Spring?
  • update Java (Java 11 is supported in Spring Boot 2.1).
  • support JUnit 5
  • support Java 11 modules
  • update readme

Split spring-boot-starter and spring-boot-autoconfigure

The starter should only contain the dependencies, while the autoconfigure contains the code. If you also make the deps optional on the autoconfigure module (see #25), then ConditionalOnClass would make sure the code doesn't break even if there is no wiremock on the classpath.

Support Spring Boot 3

When trying to use WireMockTest with Spring Boot 3, apparently no wireMockServer bean is created:

Error creating bean with name 'com.epages.stripeapp.account.AccountServiceIntegrationTests': Unsatisfied dependency expressed through field 'wireMockServer': No qualifying bean of type 'com.github.tomakehurst.wiremock.WireMockServer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.epages.stripeapp.account.AccountServiceIntegrationTests': Unsatisfied dependency expressed through field 'wireMockServer': No qualifying bean of type 'com.github.tomakehurst.wiremock.WireMockServer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713)
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693)
	at app//org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:133)
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:482)
	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1416)
	at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:396)
	at app//org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:142)
	at app//org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:97)
	at app//org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:241)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
	at app//org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at app//org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at app//org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at app//org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at app//org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at app//org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at app//org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at app//org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at app//org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at app//org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at app//org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at [email protected]/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at [email protected]/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.github.tomakehurst.wiremock.WireMockServer' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1824)
	at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1383)
	at app//org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
	at app//org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:710)
	... 47 more

Wrong representation of response headers

Example of current format:

{
    "request": {
        "method": "GET",
        "url": "/some/thing"
    },
    "response": {
        "status": 200,
        "body": "Hello world!",
        "headers": {
            "Content-Type": ["text/plain"]
        }
    }
}

This is how wiremock wants the format (according to the docs http://wiremock.org/docs/stubbing/ )

{
    "request": {
        "method": "GET",
        "url": "/some/thing"
    },
    "response": {
        "status": 200,
        "body": "Hello world!",
        "headers": {
            "Content-Type": "text/plain"
        }
    }
}

Remove mockmvc dependency

The wiremock snippets do not require mockmvc, but only some static helper methods that are deprecated at the moment. We should remove these with the next minor version bump, and then move the dependency to spring-restdocs-core.

MockMvcRequestConverter wrong stub generation for DELETE method

I found an issue at MockMvcRequestConverter.
For example we have batch delete Method that uses HTTP DELETE example below:

DELETE /users?id=1&id=2&id=3

In such scenario document generator can't generate correct stub. I found the place where the problem exists. Below in convert method there is implicitly "GET" only method covered. What to do in case with DELETE?

@Override
    public OperationRequest convert(MockHttpServletRequest mockRequest) {
        try {
            HttpHeaders headers = extractHeaders(mockRequest);
            Parameters parameters = extractParameters(mockRequest);
            List<OperationRequestPart> parts = extractParts(mockRequest);
            Collection<RequestCookie> cookies = extractCookies(mockRequest, headers);
            String queryString = mockRequest.getQueryString();
            if (!StringUtils.hasText(queryString)
                    && "GET".equals(mockRequest.getMethod())) {
                queryString = parameters.toQueryString();
            }
            return new OperationRequestFactory().create(
                    URI.create(
                            getRequestUri(mockRequest) + (StringUtils.hasText(queryString)
                                    ? "?" + queryString : "")),
                    HttpMethod.valueOf(mockRequest.getMethod()),
                    FileCopyUtils.copyToByteArray(mockRequest.getInputStream()), headers,
                    parameters, parts, cookies);
        }
        catch (Exception ex) {
            throw new ConversionException(ex);
        }
    }

restdocs-client:test fails

I followed the instructions in the README to build the project from source:

./gradlew restdocs-wiremock:build restdocs-wiremock:publishToMavenLocal
./gradlew restdocs-server:build restdocs-server:publishToMavenLocal
./gradlew restdocs-client:build

Then I get:

:restdocs-client:test

com.example.client.NoteServiceTest > should_1_use_dedicated_wiremock_stub FAILED
    org.springframework.web.client.HttpClientErrorException at NoteServiceTest.java:37

com.example.client.NoteServiceTest > should_3_use_default_wiremock_stubs FAILED
    org.springframework.web.client.HttpClientErrorException at NoteServiceTest.java:48
2017-04-26 16:06:37.878  INFO 4664 --- [       Thread-5] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@377c5df4: startup date [Wed Apr 26 16:06:35 CEST 2017]; root of context hierarchy

5 tests completed, 2 failed
:restdocs-client:test FAILED

FAILURE: Build failed with an exception.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.