Sync docs from master to gh-pages

This commit is contained in:
buildmaster
2018-03-07 20:23:06 +00:00
parent 94090e1e7c
commit 8dfcde2af0
6 changed files with 699 additions and 20 deletions

View File

@@ -45,7 +45,7 @@ sides of the communication. You can pass the values:</p><p>Either via the <code
value(stub(...), test(...))
value(client(...), server(...))</pre><p>or using the <code class="literal">$()</code> method</p><pre class="programlisting">$(consumer(...), producer(...))
$(stub(...), test(...))
$(client(...), server(...))</pre><p>You can read more about this in the <a class="link" href="https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl" target="_top">Contract DSL section</a>.</p><p>Calling <code class="literal">value()</code> or <code class="literal">$()</code> tells Spring Cloud Contract that you will be passing a dynamic value.
$(client(...), server(...))</pre><p>You can read more about this in the <a class="link" href="https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_contract_dsl" target="_top">Contract DSL section</a>.</p><p>Calling <code class="literal">value()</code> or <code class="literal">$()</code> tells Spring Cloud Contract that you will be passing a dynamic value.
Inside the <code class="literal">consumer()</code> method you pass the value that should be used on the consumer side (in the generated stub).
Inside the <code class="literal">producer()</code> method you pass the value that should be used on the producer side (in the generated test).</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>If on one side you have passed the regular expression and you haven&#8217;t passed the other, then the
other side will get auto-generated.</p></td></tr></table></div><p>Most often you will use that method together with the <code class="literal">regex</code> helper method. E.g. <code class="literal">consumer(regex('[0-9]{10}'))</code>.</p><p>To sum it up the contract for the aforementioned scenario would look more or less like this (the regular expression

View File

@@ -24,7 +24,197 @@ sides.</li><li class="listitem">To generate boilerplate test code to be used on
features in the contracts. Assume that we have a business use case of fraud check. If a
user can be a fraud for 100 different reasons, we would assume that you would create 2
contracts, one for the positive case and one for the negative case. Contract tests are
used to test contracts between applications and not to simulate full behavior.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_how_it_works" href="#_how_it_works"></a>2.3&nbsp;How It Works</h2></div></div></div><p>This section explores how Spring Cloud Contract Verifier with Stub Runner works.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_defining_the_contract" href="#_defining_the_contract"></a>2.3.1&nbsp;Defining the contract</h3></div></div></div><p>As consumers of services, we need to define what exactly we want to achieve. We need to
used to test contracts between applications and not to simulate full behavior.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_how_it_works" href="#_how_it_works"></a>2.3&nbsp;How It Works</h2></div></div></div><p>This section explores how Spring Cloud Contract Verifier with Stub Runner works.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_a_three_second_tour" href="#_a_three_second_tour"></a>2.3.1&nbsp;A three second tour</h3></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_on_the_producer_side" href="#_on_the_producer_side"></a>On the Producer Side</h4></div></div></div><p>In order to start working with <code class="literal">Spring Cloud Contract</code>, add files with REST/ messaging contracts expressed in either
Groovy DSL or YAML to the contracts directory set by the
<code class="literal">contractsDslDir</code> property, by default <code class="literal">$rootDir/src/test/resources/contracts</code>.</p><p>Then, add Spring Cloud Contract Verifier dependency and plugin to your build file:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-starter-contract-verifier<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;scope&gt;</span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/scope&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;plugin&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;version&gt;</span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/version&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;extensions&gt;</span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/extensions&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/plugin&gt;</span></pre><p>Now, running <code class="literal">./mvnw clean install</code> will cause tests that verify the application
compliance with the added contracts to be automatically generated, by default under <code class="literal">org.springframework.cloud.contract.verifier.tests.</code>.</p><p>As the implementation of the functionalities described by the contracts is not yet present,
the tests will fail.</p><p>To make them pass, the correct implementation of either handling HTTP requests or messages
will have to be added. Also, a correct base test class for auto-generated tests needs to be added to the project.
This class will be extended by all the auto-generated tests and it should contain all the setup
necessary to run them (for example <code class="literal">RestAssuredMockMvc</code> controller setup or messaging test setup).</p><p>Once the implementation and the test base class are in place, the tests will pass, and both the application
and the stub artifacts will be built and installed in the local Maven repository. The changes can now be merged
and both the application and the stub artifacts may be published in an online repository.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_on_the_consumer_side" href="#_on_the_consumer_side"></a>On the Consumer Side</h4></div></div></div><p><code class="literal">Spring Cloud Contract Stub Runner</code> can be used in the integration tests to get a running WireMock instance/
messaging route that simulates the actual service.</p><p>Add the dependency to <code class="literal">Spring Cloud Contract Stub Runner</code>:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-starter-contract-stub-runner<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;scope&gt;</span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/scope&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><p>Get the Producer-side stubs installed in your Maven repository by either:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">checking out the Producer side repository, adding contracts and generating the stubs by running:</li></ul></div><pre class="programlisting">$ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">cd</span> local-http-server-repo
$ ./mvnw clean install -DskipTests</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>The tests are being skipped because the Producer-side contract implementation is not in place yet,
so the automatically-generated contract tests would fail;</p></td></tr></table></div><p>or:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">getting already existing producer service stubs from a remote repository; to do this, simply pass the
stub artifact ids and artifact repository url as <code class="literal">Spring Cloud Contract Stub Runner</code> properties:</li></ul></div><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ids</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'com.example:http-server-dsl:+:stubs:8080'</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> repositoryRoot</span>: http://repo.spring.io/libs-snapshot</pre><p>Now just annotate your test class with <code class="literal">@AutoConfigureStubRunner</code>. In the annotation, provide
the group-id and artifact-id for <code class="literal">Spring Cloud Contract Stub Runner</code> to run the collaborators' stubs for you.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>Use the <code class="literal">REMOTE</code> stubsMode when downloading stubs from an online repository and <code class="literal">LOCAL</code> for offline work.</p></td></tr></table></div><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
<em><span class="hl-annotation" style="color: gray">@SpringBootTest(webEnvironment=WebEnvironment.NONE)</span></em>
<em><span class="hl-annotation" style="color: gray">@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)</span></em>
<em><span class="hl-annotation" style="color: gray">@DirtiesContext</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> LoanApplicationServiceTests {</pre><p>Now in your integration test, you will be able to receive stubbed versions of HTTP responses or messages that are
expected to be emitted by the collaborator service.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_a_three_minute_tour" href="#_a_three_minute_tour"></a>2.3.2&nbsp;A three minute tour</h3></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_on_the_producer_side_2" href="#_on_the_producer_side_2"></a>On the Producer Side</h4></div></div></div><p>In order to start working with <code class="literal">Spring Cloud Contract</code>, add files with REST/ messaging contracts expressed in either
Groovy DSL or YAML to the contracts directory set by the
<code class="literal">contractsDslDir</code> property, by default <code class="literal">$rootDir/src/test/resources/contracts</code>.</p><p>For the HTTP stubs, a contract defines what kind of response should be returned for a given request (taking into account the HTTP
methods, urls, headers, status codes, etc.). A sample HTTP stub contract in Groovy DSL would look like this:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> contracts
org.springframework.cloud.contract.spec.Contract.make {
request {
method <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'PUT'</span>
url <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'/fraudcheck'</span>
body([
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"client.id"</span>: $(regex(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'[0-9]{10}'</span>)),
loanAmount: <span class="hl-number">99999</span>
])
headers {
contentType(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'application/json'</span>)
}
}
response {
status <span class="hl-number">200</span>
body([
fraudCheckStatus: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FRAUD"</span>,
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"rejection.reason"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Amount too high"</span>
])
headers {
contentType(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'application/json'</span>)
}
}
}</pre><p>While the same contract expressed in YAML would look the following way:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">request</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> method</span>: PUT
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> url</span>: /fraudcheck
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> body</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> "client.id"</span>: <span class="hl-number">1234567890</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> loanAmount</span>: <span class="hl-number">99999</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> headers</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> Content-Type</span>: application/json
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> matchers</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> body</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - path</span>: $.[<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'client.id'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> type</span>: by_regex
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> value</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-9]{10}"</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">response</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> status</span>: <span class="hl-number">200</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> body</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> fraudCheckStatus</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FRAUD"</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> "rejection.reason"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Amount too high"</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> headers</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> Content-Type</span>: application/json;charset=UTF-<span class="hl-number">8</span></pre><p>In the case of messaging, the input and the output messages can be defined (taking into account from and
where to it was sent, the message body and header), as well as the methods that should be called after the message
is received or the methods that, when called, should trigger a message.
An example of a Camel messaging contract expressed in Groovy DSL whould look like this:</p><pre class="programlisting">def contractDsl = Contract.make {
label <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'some_label'</span>
input {
messageFrom(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'jms:delete'</span>)
messageBody([
bookName: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'foo'</span>
])
messageHeaders {
header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'sample'</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'header'</span>)
}
assertThat(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'bookWasDeleted()'</span>)
}
}</pre><p>While, the same contract expressed in YAML would look as in the code below:</p><pre class="programlisting">label: some_label
input:
messageFrom: jms:delete
messageBody:
bookName: 'foo'
messageHeaders:
sample: header
assertThat: bookWasDeleted()</pre><p>Then, add Spring Cloud Contract Verifier dependency and plugin to your build file:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-starter-contract-verifier<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;scope&gt;</span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/scope&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;plugin&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;version&gt;</span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/version&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;extensions&gt;</span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/extensions&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/plugin&gt;</span></pre><p>Now, running <code class="literal">./mvnw clean install</code> will cause tests that verify the application
compliance with the added contracts to be automatically generated, by default under <code class="literal">org.springframework.cloud.contract.verifier.tests.</code>.</p><p>A sample auto-generated test for an HTTP contract would look the following way:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Test</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> validate_shouldMarkClientAsFraud() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// given:</span>
MockMvcRequestSpecification request = given()
.header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1+json"</span>)
.body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"{\"client.id\":\"1234567890\",\"loanAmount\":99999}"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when:</span>
ResponseOptions response = given().spec(request)
.put(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/fraudcheck"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// then:</span>
assertThat(response.statusCode()).isEqualTo(<span class="hl-number">200</span>);
assertThat(response.header(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Content-Type"</span>)).matches(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"application/vnd.fraud.v1.json.*"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// and:</span>
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"['fraudCheckStatus']"</span>).matches(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[A-Z]{5}"</span>);
assertThatJson(parsedJson).field(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"['rejection.reason']"</span>).isEqualTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Amount too high"</span>);
}</pre><p>The sample above uses Spring&#8217;s <code class="literal">MockMvc</code> to run the tests. This is the default test mode for HTTP
contracts, however also JAX-RX client and explicit HTTP invocations can be used as well (just change
the <code class="literal">testMode</code> property of the plugin to <code class="literal">JAX-RS</code> or <code class="literal">EXPLICIT</code>.</p><p>Apart from the default JUnit, you can also use Spock tests, instead, by setting the plugin <code class="literal">testFramework</code>
property to <code class="literal">Spock</code>.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>You can now also generate WireMock scenarios based on the contracts, by including an order number followed by
an underscore at the beginning of the contract file names.</p></td></tr></table></div><p>A sample auto-generated test in Spock for a messaging stub contract would look similar to this:</p><pre class="literallayout">[source,groovy,indent=0]</pre><pre class="screen">given:
ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
\'\'\'{"bookName":"foo"}\'\'\',
['sample': 'header']
)
when:
contractVerifierMessaging.send(inputMessage, 'jms:delete')
then:
noExceptionThrown()
bookWasDeleted()</pre><p>As the implementation of the functionalities described by the contracts is not yet present,
the tests will fail.</p><p>To make them pass, the correct implementation of handling either HTTP requests or messages
will have to be added. Also, a correct base test class for auto-generated tests needs to be added to the project.
This class will be extended by all the auto-generated tests and it should contain all the setup
necessary to run them (for example <code class="literal">RestAssuredMockMvc</code> controller setup or messaging test setup).</p><p>Once the implementation and the test base class are in place, the tests will pass, and both the application
and the stub artifacts will be built and installed in the local Maven repository. Information about
installing the stubs jar to the local repository will appear in the logs:</p><pre class="programlisting">[INFO] --- spring-cloud-contract-maven-plugin:<span class="hl-number">1.0</span>.<span class="hl-number">0.</span>BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar
[INFO]
[INFO] --- maven-jar-plugin:<span class="hl-number">2.6</span>:jar (default-jar) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:<span class="hl-number">1.5</span>.<span class="hl-number">5.</span>BUILD-SNAPSHOT:repackage (default) @ http-server ---
[INFO]
[INFO] --- maven-install-plugin:<span class="hl-number">2.5</span>.<span class="hl-number">2</span>:install (default-install) @ http-server ---
[INFO] Installing /some/path/http-server/target/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.jar
[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT.pom
[INFO] Installing /some/path/http-server/target/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar</pre><p>The changes can now be merged and both the application and the stub artifacts may be published in an online repository.</p><p><span class="strong"><strong>Docker Project</strong></span></p><p>In order to enable working with contracts while creating applications in non-JVM technologies,
the <code class="literal">springcloud/spring-cloud-contract</code> Docker image has been created. It contains a project that will
automatically generate tests for HTTP contracts and execute them in <code class="literal">EXPLICIT</code> test mode, then, if
the tests pass, generate Wiremock stubs and -optionally- publish them to an artifact manager. In order to use the
image, it&#8217;s sufficient to mount the contracts into the <code class="literal">/contracts</code> directory and set a few environment variables.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_on_the_consumer_side_2" href="#_on_the_consumer_side_2"></a>On the Consumer Side</h4></div></div></div><p><code class="literal">Spring Cloud Contract Stub Runner</code> can be used in the integration tests to get a running WireMock instance/
messaging route that simulates the actual service.</p><p>Add the dependency to <code class="literal">Spring Cloud Contract Stub Runner</code>:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;dependency&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;groupId&gt;</span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/groupId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;artifactId&gt;</span>spring-cloud-starter-contract-stub-runner<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/artifactId&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;scope&gt;</span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/scope&gt;</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><p>Get the Producer-side stubs installed in your Maven repository by either:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">checking out the Producer side repository, adding contracts and generating the stubs by running:</li></ul></div><pre class="programlisting">$ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">cd</span> local-http-server-repo
$ ./mvnw clean install -DskipTests</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>The tests are being skipped because the Producer-side contract implementation is not in place yet,
so the automatically-generated contract tests would fail;</p></td></tr></table></div><p>or:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">getting already existing producer service stubs from a remote repository; to do this, simply pass the
stub artifact ids and artifact repository url as <code class="literal">Spring Cloud Contract Stub Runner</code> properties:</li></ul></div><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">stubrunner</span>:
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ids</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'com.example:http-server-dsl:+:stubs:8080'</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> repositoryRoot</span>: http://repo.spring.io/libs-snapshot</pre><p>Now just annotate your test class with <code class="literal">@AutoConfigureStubRunner</code>. In the annotation, provide
the group-id and artifact-id for <code class="literal">Spring Cloud Contract Stub Runner</code> to run the collaborators' stubs for you.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>Use the <code class="literal">REMOTE</code> stubsMode when downloading stubs from an online repository and <code class="literal">LOCAL</code> for offline work.</p></td></tr></table></div><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
<em><span class="hl-annotation" style="color: gray">@SpringBootTest(webEnvironment=WebEnvironment.NONE)</span></em>
<em><span class="hl-annotation" style="color: gray">@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)</span></em>
<em><span class="hl-annotation" style="color: gray">@DirtiesContext</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> LoanApplicationServiceTests {</pre><p>Now in your integration test, you will be able to receive stubbed versions of HTTP responses or messages that are
expected to be emitted by the collaborator service. You will see entries similar to theses in the build logs:</p><pre class="programlisting"><span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.403</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Desired version is + - will try to resolve the latest version
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.438</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is <span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.439</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact com.example:http-server:jar:stubs:<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT using remote repositories []
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.451</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact com.example:http-server:jar:stubs:<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.465</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT/http-server-<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT-stubs.jar]
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">25.475</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/var/folders/<span class="hl-number">0</span>p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
<span class="hl-number">2016</span>-<span class="hl-number">07</span>-<span class="hl-number">19</span> <span class="hl-number">14</span>:<span class="hl-number">22</span>:<span class="hl-number">27.737</span> INFO <span class="hl-number">41050</span> --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:<span class="hl-number">0.0</span>.<span class="hl-number">1</span>-SNAPSHOT:stubs=<span class="hl-number">8080</span>}]</pre></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_defining_the_contract" href="#_defining_the_contract"></a>2.3.3&nbsp;Defining the contract</h3></div></div></div><p>As consumers of services, we need to define what exactly we want to achieve. We need to
formulate our expectations. That is why we write contracts.</p><p>Assume that you want to send a request containing the ID of a client company and the
amount it wants to borrow from us. You also want to send it to the /fraudcheck url via
the PUT method.</p><p><b>Groovy DSL.&nbsp;</b>
@@ -138,7 +328,7 @@ response: # (7)
#(9) - and JSON body equal to
# { "fraudCheckStatus": "FRAUD", "rejectionReason": "Amount too high" }
#(10) - with header `Content-Type` equal to `application/json;charset=UTF-8`</pre><p>
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_side" href="#_client_side"></a>2.3.2&nbsp;Client Side</h3></div></div></div><p>Spring Cloud Contract generates stubs, which you can use during client-side testing.
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_side" href="#_client_side"></a>2.3.4&nbsp;Client Side</h3></div></div></div><p>Spring Cloud Contract generates stubs, which you can use during client-side testing.
You get a running WireMock instance/Messaging route that simulates the service.
You would like to feed that instance with a proper stub definition.</p><p>At some point in time, you need to send a request to the Fraud Detection service.</p><pre class="programlisting">ResponseEntity&lt;FraudServiceResponse&gt; response =
restTemplate.exchange(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://localhost:"</span> + port + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/fraudcheck"</span>, HttpMethod.PUT,
@@ -150,7 +340,7 @@ You would like to feed that instance with a proper stub definition.</p><p>At som
<em><span class="hl-annotation" style="color: gray">@DirtiesContext</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> LoanApplicationServiceTests {</pre><p>After that, during the tests, Spring Cloud Contract automatically finds the stubs
(simulating the real service) in the Maven repository and exposes them on a configured
(or random) port.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_server_side" href="#_server_side"></a>2.3.3&nbsp;Server Side</h3></div></div></div><p>Since you are developing your stub, you need to be sure that it actually resembles your
(or random) port.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_server_side" href="#_server_side"></a>2.3.5&nbsp;Server Side</h3></div></div></div><p>Since you are developing your stub, you need to be sure that it actually resembles your
concrete implementation. You cannot have a situation where your stub acts in one way and
your application behaves in a different way, especially in production.</p><p>To ensure that your application behaves the way you define in your stub, tests are
generated from the stub you provide.</p><p>The autogenerated test looks, more or less, like this:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Test</span></em>
@@ -383,7 +573,7 @@ of an identifier or a timestamp, you need not hardcode a value. You want to allo
different ranges of values. To enable ranges of values, you can set regular expressions
matching those values for the consumer side. You can provide the body by means of either
a map notation or String with interpolations.
<a class="link" href="https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl" target="_top">Consult the docs
<a class="link" href="https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_contract_dsl" target="_top">Consult the docs
for more information.</a> We highly recommend using the map notation!</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>You must understand the map notation in order to set up contracts. Please read the
<a class="link" href="http://groovy-lang.org/json.html" target="_top">Groovy docs regarding JSON</a>.</p></td></tr></table></div><p>The previously shown contract is an agreement between two sides that:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p class="simpara">if an HTTP request is sent with all of</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">a <code class="literal">PUT</code> method on the <code class="literal">/fraudcheck</code> endpoint,</li><li class="listitem">a JSON body with a <code class="literal">client.id</code> that matches the regular expression <code class="literal">[0-9]{10}</code> and
<code class="literal">loanAmount</code> equal to <code class="literal">99999</code>,</li><li class="listitem">and a <code class="literal">Content-Type</code> header with a value of <code class="literal">application/vnd.fraud.v1+json</code>,</li></ul></div></li><li class="listitem"><p class="simpara">then an HTTP response is sent to the consumer that</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">has status <code class="literal">200</code>,</li><li class="listitem">contains a JSON body with the <code class="literal">fraudCheckStatus</code> field containing a value <code class="literal">FRAUD</code> and
@@ -441,7 +631,7 @@ Application service</code>):</p><p>Add the <code class="literal">Spring Cloud Co
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">&lt;/dependency&gt;</span></pre><p>Annotate your test class with <code class="literal">@AutoConfigureStubRunner</code>. In the annotation, provide the
<code class="literal">group-id</code> and <code class="literal">artifact-id</code> for the Stub Runner to download the stubs of your
collaborators. (Optional step) Because you&#8217;re playing with the collaborators offline, you
can also provide the offline work switch.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
can also provide the offline work switch (<code class="literal">StubRunnerProperties.StubsMode.LOCAL</code>).</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
<em><span class="hl-annotation" style="color: gray">@SpringBootTest(webEnvironment=WebEnvironment.NONE)</span></em>
<em><span class="hl-annotation" style="color: gray">@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)</span></em>

View File

@@ -1,6 +1,6 @@
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>5.&nbsp;Spring Cloud Contract Verifier Messaging</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_verifier_setup.html" title="4.&nbsp;Spring Cloud Contract Verifier Setup"><link rel="next" href="multi__spring_cloud_contract_stub_runner.html" title="6.&nbsp;Spring Cloud Contract Stub Runner"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;Spring Cloud Contract Verifier Messaging</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_setup.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="multi__spring_cloud_contract_stub_runner.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_contract_verifier_messaging" href="#_spring_cloud_contract_verifier_messaging"></a>5.&nbsp;Spring Cloud Contract Verifier Messaging</h1></div></div></div><p>Spring Cloud Contract Verifier lets you verify applications that uses messaging as a
<title>5.&nbsp;Spring Cloud Contract Verifier Messaging</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="up" href="multi_spring-cloud-contract.html" title="Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_verifier_setup.html" title="4.&nbsp;Spring Cloud Contract Verifier Setup"><link rel="next" href="multi__spring_cloud_contract_stub_runner.html" title="6.&nbsp;Spring Cloud Contract Stub Runner"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.&nbsp;Spring Cloud Contract Verifier Messaging</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_verifier_setup.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="multi__spring_cloud_contract_stub_runner.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_contract_verifier_messaging" href="#_spring_cloud_contract_verifier_messaging"></a>5.&nbsp;Spring Cloud Contract Verifier Messaging</h1></div></div></div><p>Spring Cloud Contract Verifier lets you verify applications that use messaging as a
means of communication. All of the integrations shown in this document work with Spring,
but you can also create one of your own and use that.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_integrations" href="#_integrations"></a>5.1&nbsp;Integrations</h2></div></div></div><p>You can use one of the following four integration configurations:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Apache Camel</li><li class="listitem">Spring Integration</li><li class="listitem">Spring Cloud Stream</li><li class="listitem">Spring AMQP</li></ul></div><p>Since we use Spring Boot, if you have added one of these libraries to the classpath, all
the messaging configuration is automatically set up.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Remember to put <code class="literal">@AutoConfigureMessageVerifier</code> on the base class of your

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -168,6 +168,305 @@ used to test contracts between applications and not to simulate full behavior.</
<section xml:id="_how_it_works">
<title>How It Works</title>
<simpara>This section explores how Spring Cloud Contract Verifier with Stub Runner works.</simpara>
<section xml:id="_a_three_second_tour">
<title>A three second tour</title>
<section xml:id="_on_the_producer_side">
<title>On the Producer Side</title>
<simpara>In order to start working with <literal>Spring Cloud Contract</literal>, add files with REST/ messaging contracts expressed in either
Groovy DSL or YAML to the contracts directory set by the
<literal>contractsDslDir</literal> property, by default <literal>$rootDir/src/test/resources/contracts</literal>.</simpara>
<simpara>Then, add Spring Cloud Contract Verifier dependency and plugin to your build file:</simpara>
<programlisting language="xml" linenumbering="unnumbered">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-starter-contract-verifier&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</programlisting>
<programlisting language="xml" linenumbering="unnumbered">&lt;plugin&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-contract-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;${spring-cloud-contract.version}&lt;/version&gt;
&lt;extensions&gt;true&lt;/extensions&gt;
&lt;/plugin&gt;</programlisting>
<simpara>Now, running <literal>./mvnw clean install</literal> will cause tests that verify the application
compliance with the added contracts to be automatically generated, by default under <literal>org.springframework.cloud.contract.verifier.tests.</literal>.</simpara>
<simpara>As the implementation of the functionalities described by the contracts is not yet present,
the tests will fail.</simpara>
<simpara>To make them pass, the correct implementation of either handling HTTP requests or messages
will have to be added. Also, a correct base test class for auto-generated tests needs to be added to the project.
This class will be extended by all the auto-generated tests and it should contain all the setup
necessary to run them (for example <literal>RestAssuredMockMvc</literal> controller setup or messaging test setup).</simpara>
<simpara>Once the implementation and the test base class are in place, the tests will pass, and both the application
and the stub artifacts will be built and installed in the local Maven repository. The changes can now be merged
and both the application and the stub artifacts may be published in an online repository.</simpara>
</section>
<section xml:id="_on_the_consumer_side">
<title>On the Consumer Side</title>
<simpara><literal>Spring Cloud Contract Stub Runner</literal> can be used in the integration tests to get a running WireMock instance/
messaging route that simulates the actual service.</simpara>
<simpara>Add the dependency to <literal>Spring Cloud Contract Stub Runner</literal>:</simpara>
<programlisting language="xml" linenumbering="unnumbered">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-starter-contract-stub-runner&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</programlisting>
<simpara>Get the Producer-side stubs installed in your Maven repository by either:</simpara>
<itemizedlist>
<listitem>
<simpara>checking out the Producer side repository, adding contracts and generating the stubs by running:</simpara>
</listitem>
</itemizedlist>
<programlisting language="bash" linenumbering="unnumbered">$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests</programlisting>
<tip>
<simpara>The tests are being skipped because the Producer-side contract implementation is not in place yet,
so the automatically-generated contract tests would fail;</simpara>
</tip>
<simpara>or:</simpara>
<itemizedlist>
<listitem>
<simpara>getting already existing producer service stubs from a remote repository; to do this, simply pass the
stub artifact ids and artifact repository url as <literal>Spring Cloud Contract Stub Runner</literal> properties:</simpara>
</listitem>
</itemizedlist>
<programlisting language="yaml" linenumbering="unnumbered">stubrunner:
ids: 'com.example:http-server-dsl:+:stubs:8080'
repositoryRoot: http://repo.spring.io/libs-snapshot</programlisting>
<simpara>Now just annotate your test class with <literal>@AutoConfigureStubRunner</literal>. In the annotation, provide
the group-id and artifact-id for <literal>Spring Cloud Contract Stub Runner</literal> to run the collaborators' stubs for you.</simpara>
<tip>
<simpara>Use the <literal>REMOTE</literal> stubsMode when downloading stubs from an online repository and <literal>LOCAL</literal> for offline work.</simpara>
</tip>
<programlisting language="java" linenumbering="unnumbered">@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {</programlisting>
<simpara>Now in your integration test, you will be able to receive stubbed versions of HTTP responses or messages that are
expected to be emitted by the collaborator service.</simpara>
</section>
</section>
<section xml:id="_a_three_minute_tour">
<title>A three minute tour</title>
<section xml:id="_on_the_producer_side_2">
<title>On the Producer Side</title>
<simpara>In order to start working with <literal>Spring Cloud Contract</literal>, add files with REST/ messaging contracts expressed in either
Groovy DSL or YAML to the contracts directory set by the
<literal>contractsDslDir</literal> property, by default <literal>$rootDir/src/test/resources/contracts</literal>.</simpara>
<simpara>For the HTTP stubs, a contract defines what kind of response should be returned for a given request (taking into account the HTTP
methods, urls, headers, status codes, etc.). A sample HTTP stub contract in Groovy DSL would look like this:</simpara>
<programlisting language="groovy" linenumbering="unnumbered">package contracts
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'PUT'
url '/fraudcheck'
body([
"client.id": $(regex('[0-9]{10}')),
loanAmount: 99999
])
headers {
contentType('application/json')
}
}
response {
status 200
body([
fraudCheckStatus: "FRAUD",
"rejection.reason": "Amount too high"
])
headers {
contentType('application/json')
}
}
}</programlisting>
<simpara>While the same contract expressed in YAML would look the following way:</simpara>
<programlisting language="yaml" linenumbering="unnumbered">request:
method: PUT
url: /fraudcheck
body:
"client.id": 1234567890
loanAmount: 99999
headers:
Content-Type: application/json
matchers:
body:
- path: $.['client.id']
type: by_regex
value: "[0-9]{10}"
response:
status: 200
body:
fraudCheckStatus: "FRAUD"
"rejection.reason": "Amount too high"
headers:
Content-Type: application/json;charset=UTF-8</programlisting>
<simpara>In the case of messaging, the input and the output messages can be defined (taking into account from and
where to it was sent, the message body and header), as well as the methods that should be called after the message
is received or the methods that, when called, should trigger a message.
An example of a Camel messaging contract expressed in Groovy DSL whould look like this:</simpara>
<programlisting language="groovy" linenumbering="unnumbered">def contractDsl = Contract.make {
label 'some_label'
input {
messageFrom('jms:delete')
messageBody([
bookName: 'foo'
])
messageHeaders {
header('sample', 'header')
}
assertThat('bookWasDeleted()')
}
}</programlisting>
<simpara>While, the same contract expressed in YAML would look as in the code below:</simpara>
<programlisting language="yml" linenumbering="unnumbered">label: some_label
input:
messageFrom: jms:delete
messageBody:
bookName: 'foo'
messageHeaders:
sample: header
assertThat: bookWasDeleted()</programlisting>
<simpara>Then, add Spring Cloud Contract Verifier dependency and plugin to your build file:</simpara>
<programlisting language="xml" linenumbering="unnumbered">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-starter-contract-verifier&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</programlisting>
<programlisting language="xml" linenumbering="unnumbered">&lt;plugin&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-contract-maven-plugin&lt;/artifactId&gt;
&lt;version&gt;${spring-cloud-contract.version}&lt;/version&gt;
&lt;extensions&gt;true&lt;/extensions&gt;
&lt;/plugin&gt;</programlisting>
<simpara>Now, running <literal>./mvnw clean install</literal> will cause tests that verify the application
compliance with the added contracts to be automatically generated, by default under <literal>org.springframework.cloud.contract.verifier.tests.</literal>.</simpara>
<simpara>A sample auto-generated test for an HTTP contract would look the following way:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Test
public void validate_shouldMarkClientAsFraud() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/vnd.fraud.v1+json")
.body("{\"client.id\":\"1234567890\",\"loanAmount\":99999}");
// when:
ResponseOptions response = given().spec(request)
.put("/fraudcheck");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/vnd.fraud.v1.json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['fraudCheckStatus']").matches("[A-Z]{5}");
assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high");
}</programlisting>
<simpara>The sample above uses Spring&#8217;s <literal>MockMvc</literal> to run the tests. This is the default test mode for HTTP
contracts, however also JAX-RX client and explicit HTTP invocations can be used as well (just change
the <literal>testMode</literal> property of the plugin to <literal>JAX-RS</literal> or <literal>EXPLICIT</literal>.</simpara>
<simpara>Apart from the default JUnit, you can also use Spock tests, instead, by setting the plugin <literal>testFramework</literal>
property to <literal>Spock</literal>.</simpara>
<tip>
<simpara>You can now also generate WireMock scenarios based on the contracts, by including an order number followed by
an underscore at the beginning of the contract file names.</simpara>
</tip>
<simpara>A sample auto-generated test in Spock for a messaging stub contract would look similar to this:</simpara>
<literallayout class="monospaced">[source,groovy,indent=0]</literallayout>
<screen>given:
ContractVerifierMessage inputMessage = contractVerifierMessaging.create(
\'\'\'{"bookName":"foo"}\'\'\',
['sample': 'header']
)
when:
contractVerifierMessaging.send(inputMessage, 'jms:delete')
then:
noExceptionThrown()
bookWasDeleted()</screen>
<simpara>As the implementation of the functionalities described by the contracts is not yet present,
the tests will fail.</simpara>
<simpara>To make them pass, the correct implementation of handling either HTTP requests or messages
will have to be added. Also, a correct base test class for auto-generated tests needs to be added to the project.
This class will be extended by all the auto-generated tests and it should contain all the setup
necessary to run them (for example <literal>RestAssuredMockMvc</literal> controller setup or messaging test setup).</simpara>
<simpara>Once the implementation and the test base class are in place, the tests will pass, and both the application
and the stub artifacts will be built and installed in the local Maven repository. Information about
installing the stubs jar to the local repository will appear in the logs:</simpara>
<programlisting language="bash" linenumbering="unnumbered">[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar</programlisting>
<simpara>The changes can now be merged and both the application and the stub artifacts may be published in an online repository.</simpara>
<simpara><emphasis role="strong">Docker Project</emphasis></simpara>
<simpara>In order to enable working with contracts while creating applications in non-JVM technologies,
the <literal>springcloud/spring-cloud-contract</literal> Docker image has been created. It contains a project that will
automatically generate tests for HTTP contracts and execute them in <literal>EXPLICIT</literal> test mode, then, if
the tests pass, generate Wiremock stubs and -optionally- publish them to an artifact manager. In order to use the
image, it&#8217;s sufficient to mount the contracts into the <literal>/contracts</literal> directory and set a few environment variables.</simpara>
</section>
<section xml:id="_on_the_consumer_side_2">
<title>On the Consumer Side</title>
<simpara><literal>Spring Cloud Contract Stub Runner</literal> can be used in the integration tests to get a running WireMock instance/
messaging route that simulates the actual service.</simpara>
<simpara>Add the dependency to <literal>Spring Cloud Contract Stub Runner</literal>:</simpara>
<programlisting language="xml" linenumbering="unnumbered">&lt;dependency&gt;
&lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
&lt;artifactId&gt;spring-cloud-starter-contract-stub-runner&lt;/artifactId&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</programlisting>
<simpara>Get the Producer-side stubs installed in your Maven repository by either:</simpara>
<itemizedlist>
<listitem>
<simpara>checking out the Producer side repository, adding contracts and generating the stubs by running:</simpara>
</listitem>
</itemizedlist>
<programlisting language="bash" linenumbering="unnumbered">$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests</programlisting>
<tip>
<simpara>The tests are being skipped because the Producer-side contract implementation is not in place yet,
so the automatically-generated contract tests would fail;</simpara>
</tip>
<simpara>or:</simpara>
<itemizedlist>
<listitem>
<simpara>getting already existing producer service stubs from a remote repository; to do this, simply pass the
stub artifact ids and artifact repository url as <literal>Spring Cloud Contract Stub Runner</literal> properties:</simpara>
</listitem>
</itemizedlist>
<programlisting language="yaml" linenumbering="unnumbered">stubrunner:
ids: 'com.example:http-server-dsl:+:stubs:8080'
repositoryRoot: http://repo.spring.io/libs-snapshot</programlisting>
<simpara>Now just annotate your test class with <literal>@AutoConfigureStubRunner</literal>. In the annotation, provide
the group-id and artifact-id for <literal>Spring Cloud Contract Stub Runner</literal> to run the collaborators' stubs for you.</simpara>
<tip>
<simpara>Use the <literal>REMOTE</literal> stubsMode when downloading stubs from an online repository and <literal>LOCAL</literal> for offline work.</simpara>
</tip>
<programlisting language="java" linenumbering="unnumbered">@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {</programlisting>
<simpara>Now in your integration test, you will be able to receive stubbed versions of HTTP responses or messages that are
expected to be emitted by the collaborator service. You will see entries similar to theses in the build logs:</simpara>
<programlisting language="bash" linenumbering="unnumbered">2016-07-19 14:22:25.403 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Desired version is + - will try to resolve the latest version
2016-07-19 14:22:25.438 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is 0.0.1-SNAPSHOT
2016-07-19 14:22:25.439 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
2016-07-19 14:22:25.451 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
2016-07-19 14:22:25.465 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
2016-07-19 14:22:25.475 INFO 41050 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
2016-07-19 14:22:27.737 INFO 41050 --- [ main] o.s.c.c.stubrunner.StubRunnerExecutor : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]</programlisting>
</section>
</section>
<section xml:id="_defining_the_contract">
<title>Defining the contract</title>
<simpara>As consumers of services, we need to define what exactly we want to achieve. We need to
@@ -644,7 +943,7 @@ of an identifier or a timestamp, you need not hardcode a value. You want to allo
different ranges of values. To enable ranges of values, you can set regular expressions
matching those values for the consumer side. You can provide the body by means of either
a map notation or String with interpolations.
<link xl:href="https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl">Consult the docs
<link xl:href="https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_contract_dsl">Consult the docs
for more information.</link> We highly recommend using the map notation!</simpara>
<tip>
<simpara>You must understand the map notation in order to set up contracts. Please read the
@@ -765,7 +1064,7 @@ Application service</literal>):</simpara>
<simpara>Annotate your test class with <literal>@AutoConfigureStubRunner</literal>. In the annotation, provide the
<literal>group-id</literal> and <literal>artifact-id</literal> for the Stub Runner to download the stubs of your
collaborators. (Optional step) Because you&#8217;re playing with the collaborators offline, you
can also provide the offline work switch.</simpara>
can also provide the offline work switch (<literal>StubRunnerProperties.StubsMode.LOCAL</literal>).</simpara>
<programlisting language="groovy" linenumbering="unnumbered">@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
@@ -1067,7 +1366,7 @@ value(client(...), server(...))</programlisting>
<programlisting language="groovy" linenumbering="unnumbered">$(consumer(...), producer(...))
$(stub(...), test(...))
$(client(...), server(...))</programlisting>
<simpara>You can read more about this in the <link xl:href="https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl">Contract DSL section</link>.</simpara>
<simpara>You can read more about this in the <link xl:href="https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_contract_dsl">Contract DSL section</link>.</simpara>
<simpara>Calling <literal>value()</literal> or <literal>$()</literal> tells Spring Cloud Contract that you will be passing a dynamic value.
Inside the <literal>consumer()</literal> method you pass the value that should be used on the consumer side (in the generated stub).
Inside the <literal>producer()</literal> method you pass the value that should be used on the producer side (in the generated test).</simpara>
@@ -2798,7 +3097,7 @@ The stubs will be here <link xl:href="http://localhost:8081/artifactory/libs-rel
</chapter>
<chapter xml:id="_spring_cloud_contract_verifier_messaging">
<title>Spring Cloud Contract Verifier Messaging</title>
<simpara>Spring Cloud Contract Verifier lets you verify applications that uses messaging as a
<simpara>Spring Cloud Contract Verifier lets you verify applications that use messaging as a
means of communication. All of the integrations shown in this document work with Spring,
but you can also create one of your own and use that.</simpara>
<section xml:id="_integrations">