@Bean
+public RestTemplate restTemplate(RestTemplateBuilder builder) {
+ return builder.build();
+}
+diff --git a/1.0.x/index.html b/1.0.x/index.html index 8ab92a6b4a..a381e73ba8 100644 --- a/1.0.x/index.html +++ b/1.0.x/index.html @@ -505,6 +505,7 @@ $(addBlockSwitches);
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.
<dependency>
+<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
@@ -2973,6 +3030,39 @@ dependencies {
By default Rest Assured 2.x is added to the classpath. However in order to give the users the +opportunity to use Rest Assured 3.x it’s enough to add it to the plugins classpath.
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
+ classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
+ classpath "io.rest-assured:rest-assured:3.0.2"
+ classpath "io.rest-assured:spring-mock-mvc:3.0.2"
+ }
+}
+
+depenendencies {
+ // all dependencies
+ // you can exclude rest-assured from spring-cloud-contract-verifier
+ testCompile "io.rest-assured:rest-assured:3.0.2"
+ testCompile "io.rest-assured:spring-mock-mvc:3.0.2"
+}
+That way the plugin will automatically see that Rest Assured 3.x is present on the classpath +and will modify the imports accordingly.
+Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:
@@ -3341,6 +3431,66 @@ class LoanApplicationServiceSpec extends Specification {You can read more in the Spring Cloud Contract Maven Plugin Docs
By default Rest Assured 2.x is added to the classpath. However in order to give the users the +opportunity to use Rest Assured 3.x it’s enough to add it to the plugins classpath.
+<plugin>
+ <groupId>org.springframework.cloud</groupId>
+ <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+ <version>${spring-cloud-contract.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <packageWithBaseClasses>com.example</packageWithBaseClasses>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.cloud</groupId>
+ <artifactId>spring-cloud-contract-verifier</artifactId>
+ <version>${spring-cloud-contract.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <version>3.0.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>spring-mock-mvc</artifactId>
+ <version>3.0.2</version>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+</plugin>
+
+<dependencies>
+ <!-- all dependencies -->
+ <!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <version>3.0.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>spring-mock-mvc</artifactId>
+ <version>3.0.2</version>
+ <scope>test</scope>
+ </dependency>
+</dependencies>
+That way the plugin will automatically see that Rest Assured 3.x is present on the classpath +and will modify the imports accordingly.
+For Snapshot / Milestone versions you have to add the following section to your pom.xml
feed the WireMock server with all JSON files that are valid WireMock definitions
can also send messages (remember to pass an implementation of MessageVerifier interface)
Check the Common properties for JUnit and Spring for more information on how to apply global configuration of Stub Runner.
|
+ Important
+ |
+
+To use the JUnit rule together with messaging you have to provide an implementation of the
+MessageVerifier interface to the rule builder (e.g. rule.messageVerifier(new MyMessageVerifier())).
+If you don’t do this then whenever you try to send a message an exception will be thrown.
+ |
+
There are cases in which 2 consumers of the same endpoint want to have 2 different responses.
+|
+ Tip
+ |
++This approach also allows you to immediately know which consumer is using which part of your API. +You can remove part of a response that your API produces and you can see which of your autogenerated tests +fails. If none fails then you can safely delete that part of the response cause nobody is using it. + | +
Let’s look at the following example for contract defined for the producer called producer.
+There are 2 consumers: foo-consumer and bar-consumer.
Consumer foo-service
request {
+ url '/foo'
+ method GET()
+}
+response {
+ status 200
+ body(
+ foo: "foo"
+ }
+}
+Consumer bar-service
request {
+ url '/foo'
+ method GET()
+}
+response {
+ status 200
+ body(
+ bar: "bar"
+ }
+}
+You can’t produce for the same request 2 different responses. That’s why you can properly package the
+contracts and then profit from the stubsPerConsumer feature.
On the producer side the consumers can have a folder that contains contracts related only to them.
+By setting the stubrunner.stubs-per-consumer flag to true we no longer register all stubs but only those that
+correspond to the consumer application’s name. In other words we’ll scan the path of every stub and
+if it contains the subfolder with name of the consumer in the path only then will it get registered.
On the foo producer side the contracts would look like this
.
+└── contracts
+ ├── bar-consumer
+ │ ├── bookReturnedForBar.groovy
+ │ └── shouldCallBar.groovy
+ └── foo-consumer
+ ├── bookReturnedForFoo.groovy
+ └── shouldCallFoo.groovy
+Being the bar-consumer consumer you can either set the spring.application.name or the stubrunner.consumer-name to bar-consumer
+Or set the test as follows:
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+ repositoryRoot = "classpath:m2repo/repository/",
+ stubsPerConsumer = true)
+@DirtiesContext
+class StubRunnerStubsPerConsumerSpec extends Specification {
+...
+}
+Then only the stubs registered under a path that contains the bar-consumer in its name (i.e. those from the
+src/test/resources/contracts/bar-consumer/some/contracts/… folder) will be allowed to be referenced.
Or set the consumer name explicitly
+@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
+@SpringBootTest
+@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
+ repositoryRoot = "classpath:m2repo/repository/",
+ consumerName = "foo-consumer",
+ stubsPerConsumer = true)
+@DirtiesContext
+class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {
+...
+}
+Then only the stubs registered under a path that contains the foo-consumer in its name (i.e. those from the
+src/test/resources/contracts/foo-consumer/some/contracts/… folder) will be allowed to be referenced.
You can check out issue 224 for more +information about the reasons behind this change.
+It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath.
-Remember to annotate your test class with @AutoConfigureMessageVerifier.
@AutoConfigureStubRunner.
It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath.
-Remember to annotate your test class with @AutoConfigureMessageVerifier.
It’s enough to have both Spring Integration and Spring Cloud Contract Stub Runner on classpath.
+Remember to annotate your test class with @AutoConfigureStubRunner.
It’s enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath.
-Remember to annotate your test class with @AutoConfigureMessageVerifier.
It’s enough to have both Spring Cloud Stream and Spring Cloud Contract Stub Runner on classpath.
+Remember to annotate your test class with @AutoConfigureStubRunner.
It’s enough to have both Spring AMQP and Spring Cloud Contract Stub Runner on the classpath and set the property stubrunner.amqp.enabled=true.
-Remember to annotate your test class with @AutoConfigureMessageVerifier.
@AutoConfigureStubRunner.
foo method to which the value matching the
dateTime: "2017-01-01T01:23:45",
time: "01:02:34",
valueWithoutAMatcher: "foo",
- valueWithTypeMatch: "string"
+ valueWithTypeMatch: "string",
+ key: [
+ 'complex.key' : 'foo'
+ ]
])
stubMatchers {
jsonPath('$.duck', byRegex("[0-9]{3}"))
@@ -7133,6 +7432,7 @@ will result in calling a foo method to which the value matching the
jsonPath('$.date', byDate())
jsonPath('$.dateTime', byTimestamp())
jsonPath('$.time', byTime())
+ jsonPath("\$.['key'].['complex.key']", byEquality())
}
headers {
contentType(applicationJson())
@@ -7161,6 +7461,9 @@ will result in calling a foo method to which the value matching the
],
valueWithMinEmpty: [],
valueWithMaxEmpty: [],
+ key: [
+ 'complex.key' : 'foo'
+ ]
])
testMatchers {
// asserts the jsonpath value against manual regex
@@ -7201,6 +7504,7 @@ will result in calling a foo method to which the value matching the
})
// will execute a method `assertThatValueIsANumber`
jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)'))
+ jsonPath("\$.['key'].['complex.key']", byEquality())
}
headers {
contentType(applicationJson())
@@ -7292,22 +7596,22 @@ assertions and the one from matchers with an and section):
{
"request" : {
"urlPath" : "/get",
- "method" : "GET",
+ "method" : "POST",
"headers" : {
"Content-Type" : {
"matches" : "application/json.*"
}
},
"bodyPatterns" : [ {
- "matchesJsonPath" : "$[?(@.valueWithoutAMatcher == 'foo')]"
+ "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
}, {
- "matchesJsonPath" : "$[?(@.valueWithTypeMatch == 'string')]"
+ "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
}, {
- "matchesJsonPath" : "$.list.some.nested[?(@.anothervalue == 4)]"
+ "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
}, {
- "matchesJsonPath" : "$.list.someother.nested[?(@.anothervalue == 4)]"
+ "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
}, {
- "matchesJsonPath" : "$.list.someother.nested[?(@.json == 'with value')]"
+ "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
}, {
"matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
}, {
@@ -7385,7 +7689,7 @@ assertions and the one from matchers with an and section):
assertThat(response.getStatus()).isEqualTo(200);
// and:
DocumentContext parsedJson = JsonPath.parse(responseAsString);
- assertThatJson(parsedJson).field("property1").isEqualTo("a");
+ assertThatJson(parsedJson).field("['property1']").isEqualTo("a");
'''
<dependency>
- <groupId>com.jayway.restassured</groupId>
- <artifactId>rest-assured</artifactId>
- <version>2.9.0</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.jayway.restassured</groupId>
- <artifactId>spring-mock-mvc</artifactId>
- <version>2.9.0</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.toomuchcoding.jsonassert</groupId>
- <artifactId>jsonassert</artifactId>
- <version>0.4.8</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.assertj</groupId>
- <artifactId>assertj-core</artifactId>
- <version>2.4.1</version>
+ <groupId>org.springframework.cloud</groupId>
+ <artifactId>spring-cloud-starter-contract-verifier</artifactId>
+ <version>${it-plugin.version}</version>
<scope>test</scope>
</dependency>