Jekyll2020-07-11T13:36:13+02:00https://www.mosfet.io/feed.xmlmos_where I develop my ideas and notes about development{"picture"=>"/img/gp1.jpg", "twitter"=>"nmosf"}Consumer-Driven Contract Testing with Pact and Java - Part II2020-06-17T14:00:00+02:002020-06-17T14:00:00+02:00https://www.mosfet.io/2020/06/17/contract-test-part2<p>The <a href="/2020/06/03/contract-tests-part1/">previous post</a> explains the principles and motivations behind
contract testing. Today we give a look to how write consumer-driven contract tests with pact and Java in a SpringBoot
application.</p>
<p>Pact foundation provides junit5 integration for creation and verification of contracts.</p>
<p>Let’s start!</p>
<h2 id="what-you-need">What you need</h2>
<p>The <a href="https://github.com/DiUS/pact-jvm">Java Pact Testing framework</a> used in this example is the <code class="highlighter-rouge">4.0.0</code>,
based on <code class="highlighter-rouge">v3</code> <a href="https://github.com/pact-foundation/pact-specification/tree/version-3">specification</a>.</p>
<p>Furthermore, you should have:</p>
<ul>
<li>jdk 1.8 or later</li>
<li>maven 3.2+</li>
<li>a bit of testing knowledge in Spring</li>
</ul>
<p>You can find all the presented code on <a href="https://github.com/kmos/contract-test-pact-java-example">github</a>.</p>
<hr />
<h2 id="the-example">The example</h2>
<p><img src="/img/contractsp2_01.png" alt="example" title="example" /></p>
<p>The proposed example is similar to the previous one seen in part I: we have a <em>provider</em> service which expose an
API that given a sentence and a timestamp, it replies an echo response enriched with local timestamp. This API <em>is consumed</em>
by another service. To summarize:</p>
<p><em>endpoint</em> <code class="highlighter-rouge">POST /api/echo</code></p>
<p><em>request body</em></p>
<pre><code class="language-JSON">{
"timestamp": 1593373353,
"sentence": "hello!"
}
</code></pre>
<p><em>response body</em></p>
<pre><code class="language-JSON">{
"phrase": "hello! sent at: 1593373353 worked at: 1593373360"
}
</code></pre>
<hr />
<h2 id="consumer-side">Consumer side</h2>
<p>We are driven by Consumer, so then we start working on consumer side: we add the pact maven dependency in consumer <code class="highlighter-rouge">pom.xml</code></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><dependency></span>
<span class="nt"><groupId></span>au.com.dius<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>pact-jvm-consumer-junit5<span class="nt"></artifactId></span>
<span class="nt"><version></span>4.0.10<span class="nt"></version></span>
<span class="nt"></dependency></span>
</code></pre></div></div>
<hr />
<h3 id="create-a-contract">create a contract</h3>
<p>Let’s start creating a junit5 test with <code class="highlighter-rouge">PactConsumerTestExt</code> junit extension:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kn">import</span> <span class="nn">au.com.dius.pact.consumer.junit5.PactConsumerTestExt</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.junit.jupiter.api.extension.ExtendWith</span><span class="o">;</span>
<span class="nd">@ExtendWith</span><span class="o">(</span><span class="nc">PactConsumerTestExt</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">class</span> <span class="nc">ConsumerContractTest</span> <span class="o">{</span>
</code></pre></div></div>
<p>in <code class="highlighter-rouge">@BeforeEach</code> method we can assert that the <code class="highlighter-rouge">mockServer</code> which will serve the contracts is correctly up:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@BeforeEach</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setUp</span><span class="o">(</span><span class="nc">MockServer</span> <span class="n">mockServer</span><span class="o">)</span> <span class="o">{</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">mockServer</span><span class="o">,</span> <span class="n">is</span><span class="o">(</span><span class="n">notNullValue</span><span class="o">()));</span>
<span class="o">}</span>
</code></pre></div></div>
<p>ok, now we can create a contract. A contract can be defined with a method <em>annotated</em> with <code class="highlighter-rouge">@Pact</code> that returns
a <code class="highlighter-rouge">RequestResponsePact</code> and provides as parameter <code class="highlighter-rouge">PactDslWithProvider</code>. All methods annotated with <code class="highlighter-rouge">@Pact</code> are used to
instrument the <em>mock server</em> through the <code class="highlighter-rouge">PactDslWithProvider</code> in this way:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Pact</span><span class="o">(</span><span class="n">provider</span> <span class="o">=</span> <span class="s">"providerMicroservice"</span><span class="o">,</span> <span class="n">consumer</span> <span class="o">=</span> <span class="s">"consumerMicroservice"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">RequestResponsePact</span> <span class="nf">echoRequest</span><span class="o">(</span><span class="nc">PactDslWithProvider</span> <span class="n">builder</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">builder</span>
<span class="o">.</span><span class="na">given</span><span class="o">(</span><span class="s">"a sentence worked at 1593373360"</span><span class="o">)</span>
<span class="o">.</span><span class="na">uponReceiving</span><span class="o">(</span><span class="s">"an echo request at 1593373353"</span><span class="o">)</span>
<span class="o">.</span><span class="na">path</span><span class="o">(</span><span class="no">API_ECHO</span><span class="o">)</span> <span class="cm">/* request */</span>
<span class="o">.</span><span class="na">method</span><span class="o">(</span><span class="s">"POST"</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">echoRequest</span><span class="o">)</span>
<span class="o">.</span><span class="na">willRespondWith</span><span class="o">()</span> <span class="cm">/* response */</span>
<span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="mi">200</span><span class="o">)</span>
<span class="o">.</span><span class="na">headers</span><span class="o">(</span><span class="n">headers</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">echoResponse</span><span class="o">)</span>
<span class="o">.</span><span class="na">toPact</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The Pact DSL provides a fluent API very similar to Spring <em>mockMvc</em>: Here we are saying that when the <em>mock server</em> receives
an <em>echoRequest</em>, it should return <em>200</em> and an <em>echoResponse</em>. The <code class="highlighter-rouge">given</code> and the <code class="highlighter-rouge">uponReceiving</code> method, define
<a href="https://martinfowler.com/bliki/GivenWhenThen.html">the specification in bdd approach</a> and the Pact testing framework,
uses the <code class="highlighter-rouge">given</code> part to bring the provider into the correct state before executing the interaction defined
in the contract.</p>
<hr />
<h4 id="matchers-build-a-response-with-pactdsljsonbody">Matchers: build a response with PactDslJsonBody</h4>
<p>in the previous step we created an interaction using two json object(<em>echoRequest</em> and <em>echoResponse</em>). On the provider side,
the test verify that the generated response is <em>perfectly</em> equal to the one defined in the contract.</p>
<p>The Pact testing framework provides also a DSL that permits the definition of different matching case in this way:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Pact</span><span class="o">(</span><span class="n">provider</span> <span class="o">=</span> <span class="s">"providerMicroservice"</span><span class="o">,</span> <span class="n">consumer</span> <span class="o">=</span> <span class="s">"consumerMicroservice"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">RequestResponsePact</span> <span class="nf">echoRequestWithDsl</span><span class="o">(</span><span class="nc">PactDslWithProvider</span> <span class="n">builder</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">PactDslJsonBody</span> <span class="n">responseWrittenWithDsl</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PactDslJsonBody</span><span class="o">()</span>
<span class="o">.</span><span class="na">stringType</span><span class="o">(</span><span class="s">"phrase"</span><span class="o">,</span> <span class="s">"hello! sent at: X worked at: Y"</span><span class="o">)</span> <span class="cm">/* match on type */</span>
<span class="o">.</span><span class="na">close</span><span class="o">()</span>
<span class="o">.</span><span class="na">asBody</span><span class="o">();</span>
<span class="k">return</span> <span class="n">builder</span>
<span class="o">.</span><span class="na">given</span><span class="o">(</span><span class="s">"WITH DSL: a sentence worked at 1593373360"</span><span class="o">)</span>
<span class="o">.</span><span class="na">uponReceiving</span><span class="o">(</span><span class="s">"an echo request at 1593373353"</span><span class="o">)</span>
<span class="o">.</span><span class="na">path</span><span class="o">(</span><span class="no">API_ECHO</span><span class="o">)</span>
<span class="o">.</span><span class="na">method</span><span class="o">(</span><span class="s">"POST"</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">echoRequest</span><span class="o">)</span>
<span class="o">.</span><span class="na">willRespondWith</span><span class="o">()</span>
<span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="mi">200</span><span class="o">)</span>
<span class="o">.</span><span class="na">headers</span><span class="o">(</span><span class="n">headers</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">responseWrittenWithDsl</span><span class="o">)</span>
<span class="o">.</span><span class="na">toPact</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Here we created a <em>response</em> with <code class="highlighter-rouge">PactDslJsonBody</code> DSL that defines a match case based on <em>type</em> instead of <em>value</em>.
It’s possible with <code class="highlighter-rouge">PactDslJsonBody</code> different match case based on regex or array length.</p>
<hr />
<h3 id="verify-the-contract">Verify the contract</h3>
<p>Now we can create the real test which verify the contract on the consumer side:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Test</span>
<span class="nd">@PactTestFor</span><span class="o">(</span><span class="n">pactMethod</span> <span class="o">=</span> <span class="s">"echoRequest"</span><span class="o">)</span>
<span class="nd">@DisplayName</span><span class="o">(</span><span class="s">"given a sentence with a timestamp, when calling producer microservice, than I receive back an echo sentence with a timestamp"</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">givenASentenceWithATimestampWhenCallingProducerThanReturnAnEchoWithATimestamp</span><span class="o">(</span><span class="nc">MockServer</span> <span class="n">mockServer</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">IOException</span> <span class="o">{</span>
<span class="nc">BasicHttpEntity</span> <span class="n">bodyRequest</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BasicHttpEntity</span><span class="o">();</span>
<span class="n">bodyRequest</span><span class="o">.</span><span class="na">setContent</span><span class="o">(</span><span class="nc">IOUtils</span><span class="o">.</span><span class="na">toInputStream</span><span class="o">(</span><span class="n">echoRequest</span><span class="o">,</span> <span class="nc">Charset</span><span class="o">.</span><span class="na">defaultCharset</span><span class="o">()));</span>
<span class="n">expectedResult</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">EchoResponse</span><span class="o">();</span>
<span class="n">expectedResult</span><span class="o">.</span><span class="na">setPhrase</span><span class="o">(</span><span class="s">"hello! sent at: 1593373353 worked at: 1593373360"</span><span class="o">);</span>
<span class="nc">HttpResponse</span> <span class="n">httpResponse</span> <span class="o">=</span> <span class="nc">Request</span><span class="o">.</span><span class="na">Post</span><span class="o">(</span><span class="n">mockServer</span><span class="o">.</span><span class="na">getUrl</span><span class="o">()</span> <span class="o">+</span> <span class="no">API_ECHO</span><span class="o">)</span>
<span class="o">.</span><span class="na">body</span><span class="o">(</span><span class="n">bodyRequest</span><span class="o">)</span>
<span class="o">.</span><span class="na">execute</span><span class="o">()</span>
<span class="o">.</span><span class="na">returnResponse</span><span class="o">();</span>
<span class="nc">ObjectMapper</span> <span class="n">objectMapper</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ObjectMapper</span><span class="o">();</span>
<span class="nc">EchoResponse</span> <span class="n">actualResult</span> <span class="o">=</span> <span class="n">objectMapper</span><span class="o">.</span><span class="na">readValue</span><span class="o">(</span><span class="n">httpResponse</span><span class="o">.</span><span class="na">getEntity</span><span class="o">().</span><span class="na">getContent</span><span class="o">(),</span> <span class="nc">EchoResponse</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="n">expectedResult</span><span class="o">,</span> <span class="n">actualResult</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p>if we run <code class="highlighter-rouge">mvn test</code> and we don’t have errors, we will see in <code class="highlighter-rouge">./target/pacts</code> a json file that use the pact formalism
for contracts. We use the generated contract in the provider-side.</p>
<hr />
<h2 id="provider-side">Provider side</h2>
<p>For the provider, we have a different dependency to add in <code class="highlighter-rouge">pom.xml</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><dependency></span>
<span class="nt"><groupId></span>au.com.dius<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>pact-jvm-provider-junit5<span class="nt"></artifactId></span>
<span class="nt"><version></span>4.0.10<span class="nt"></version></span>
<span class="nt"></dependency></span>
</code></pre></div></div>
<hr />
<h3 id="verify-the-contract-on-provider-side">Verify the contract on provider side</h3>
<p>Here is the thing: we need to verify the contract against provider implementation. In the Spring world, it’s sounds
like an <a href="https://spring.io/guides/gs/testing-web/">integration test which verify the web layer</a>. So here the magic:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@ExtendWith</span><span class="o">(</span><span class="nc">SpringExtension</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="nd">@SpringBootTest</span><span class="o">(</span><span class="n">webEnvironment</span> <span class="o">=</span> <span class="nc">SpringBootTest</span><span class="o">.</span><span class="na">WebEnvironment</span><span class="o">.</span><span class="na">DEFINED_PORT</span><span class="o">,</span> <span class="n">classes</span> <span class="o">=</span> <span class="nc">ProviderApplication</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="nd">@EnableAutoConfiguration</span>
<span class="nd">@AutoConfigureMockMvc</span>
<span class="nd">@TestPropertySource</span><span class="o">(</span><span class="n">locations</span> <span class="o">=</span> <span class="s">"classpath:application-contract-test.properties"</span><span class="o">)</span>
<span class="nd">@Provider</span><span class="o">(</span><span class="s">"providerMicroservice"</span><span class="o">)</span>
<span class="nd">@PactFolder</span><span class="o">(</span><span class="s">"../consumer/target/pacts"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ProviderContractTest</span> <span class="o">{</span>
<span class="nd">@Value</span><span class="o">(</span><span class="s">"${server.host}"</span><span class="o">)</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">serverHost</span><span class="o">;</span>
<span class="nd">@Value</span><span class="o">(</span><span class="s">"${server.port}"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">serverPort</span><span class="o">;</span>
<span class="nd">@BeforeEach</span>
<span class="kt">void</span> <span class="nf">setupTestTarget</span><span class="o">(</span><span class="nc">PactVerificationContext</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
<span class="n">context</span><span class="o">.</span><span class="na">setTarget</span><span class="o">(</span><span class="k">new</span> <span class="nc">HttpTestTarget</span><span class="o">(</span><span class="n">serverHost</span><span class="o">,</span> <span class="n">serverPort</span><span class="o">,</span> <span class="s">"/"</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@TestTemplate</span>
<span class="nd">@ExtendWith</span><span class="o">(</span><span class="nc">PactVerificationInvocationContextProvider</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">pactVerificationTestTemplate</span><span class="o">(</span><span class="nc">PactVerificationContext</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
<span class="n">context</span><span class="o">.</span><span class="na">verifyInteraction</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@State</span><span class="o">(</span><span class="s">"a sentence worked at 1593373360"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">sentenceWorkedAt1593373360</span><span class="o">()</span> <span class="o">{</span>
<span class="n">when</span><span class="o">(</span><span class="n">phraseService</span><span class="o">.</span><span class="na">echo</span><span class="o">(</span><span class="mi">1593373353</span><span class="o">,</span> <span class="s">"hello!"</span><span class="o">))</span>
<span class="o">.</span><span class="na">thenReturn</span><span class="o">(</span><span class="k">new</span> <span class="nc">Phrase</span><span class="o">(</span><span class="s">"hello! sent at: 1593373353 worked at: 1593373360"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>That’s it. As you can see, we have a <code class="highlighter-rouge">@SpringBootTest</code> with a fixed port and a <code class="highlighter-rouge">@TestPropertySource</code> that defines
it in order to attach the pact context to the application context with <code class="highlighter-rouge">host</code> and <code class="highlighter-rouge">port</code> info.
Obviously there are other ways, like random ports and so on, but the main thing here is to bind both context together.</p>
<p>Another thing here is the <code class="highlighter-rouge">@PactFolder</code> annotation that points to contracts generated by the consumer. The Pact Framework
search for contracts that belong to the service, and run the verification.</p>
<hr />
<h4 id="the-state-annotation">The <code class="highlighter-rouge">@State</code> annotation</h4>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@State</span><span class="o">(</span><span class="s">"a sentence worked at 1593373360"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">sentenceWorkedAt1593373360</span><span class="o">()</span> <span class="o">{</span>
<span class="n">when</span><span class="o">(</span><span class="n">phraseService</span><span class="o">.</span><span class="na">echo</span><span class="o">(</span><span class="mi">1593373353</span><span class="o">,</span> <span class="s">"hello!"</span><span class="o">))</span>
<span class="o">.</span><span class="na">thenReturn</span><span class="o">(</span><span class="k">new</span> <span class="nc">Phrase</span><span class="o">(</span><span class="s">"hello! sent at: 1593373353 worked at: 1593373360"</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>
<p>As previously mentioned, the <code class="highlighter-rouge">given</code> statement in the consumer contract, define with a business expression, the <code class="highlighter-rouge">state</code>
in which the system-under-test, should be during the execution. Following this approach, we define in the provider, a
method with <code class="highlighter-rouge">@state</code> annotation, that contains the commands necessary for the correct execution. In our case, we mock
the business service delegated to execute the <em>eco logic</em>. The framework executes the <code class="highlighter-rouge">state</code> method before calling
the API defined in the contracts. The real test, in this way, is “reduced” to a simple call:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="nd">@TestTemplate</span>
<span class="nd">@ExtendWith</span><span class="o">(</span><span class="nc">PactVerificationInvocationContextProvider</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">pactVerificationTestTemplate</span><span class="o">(</span><span class="nc">PactVerificationContext</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
<span class="n">context</span><span class="o">.</span><span class="na">verifyInteraction</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<hr />
<h4 id="use-a-broker">Use a broker</h4>
<p>If you have a <code class="highlighter-rouge">broker</code> that stores the contracts, you can change the <code class="highlighter-rouge">@PactFolder</code> annotation with <code class="highlighter-rouge">@PactBroker</code>
one and define the following plugin in the <code class="highlighter-rouge">pom.xml</code>:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><build></span>
<span class="nt"><plugins></span>
<span class="nt"><plugin></span>
<span class="nt"><groupId></span>au.com.dius<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>pact-jvm-provider-maven<span class="nt"></artifactId></span>
<span class="nt"><version></span>4.0.0<span class="nt"></version></span>
<span class="nt"><configuration></span>
<span class="nt"><pactDirectory></span>target/pacts<span class="nt"></pactDirectory></span>
<span class="nt"><pactBrokerUrl></span>${pact.broker.protocol}://${pact.broker.host}<span class="nt"></pactBrokerUrl></span>
<span class="nt"><projectVersion></span>${contracts.version}<span class="nt"></projectVersion></span>
<span class="nt"><trimSnapshot></span>true<span class="nt"></trimSnapshot></span>
<span class="nt"></configuration></span>
<span class="nt"></plugin></span>
<span class="nt"></plugins></span>
<span class="nt"></build></span>
</code></pre></div></div>
<hr />
<h2 id="whats-next">What’s Next</h2>
<p>We have covered how to develop and verify a simple contract with java starting from the consumer. We have used the Pact
DSL and matchers introduced in <code class="highlighter-rouge">v3</code> spec which is an interesting feature during design & testing. As previously mentioned,
you can find a complete working example in this <a href="https://github.com/kmos/contract-test-pact-java-example">github repo</a>.</p>
<p>In the next posts(I hope), we will see how deploy a broker server to store contracts and how integrate the entire flow with
a CI.</p>nmosfThe previous post explains the principles and motivations behind contract testing. Today we give a look to how write consumer-driven contract tests with pact and Java in a SpringBoot application.Consumer-Driven Contract Testing - Part I2020-06-03T14:00:00+02:002020-06-03T14:00:00+02:00https://www.mosfet.io/2020/06/03/contract-tests-part1<h2 id="introduction">Introduction</h2>
<p>This is the first of a series of blog posts about Contract Testing which cover the minimum set of theory and practice
necessary for an effective adoption in your team, from design to code integration.</p>
<p>Contract Testing is a category of testing activity where the data formats and conventions defined by two systems
(services) which communicate a business value, is tested against a Mock called “Contract”. A service <em>provides</em>
a callable API that can be <em>consumed</em> by another (or many) service which create an interaction between parties
that needs to be satisfied during the evolution and developing of services which are now coupled. The interaction
between services probably relies on a communication layer which can be slow or not reachable which can affect the test results.
For this reason, sometimes the best solution is to verify the interaction with a <a href="https://martinfowler.com/bliki/TestDouble.html">TestDouble</a>
which describe the expectations between the parties.</p>
<p>For the sake of clarity, I have <a href="https://www.youtube.com/watch?v=oxbS9Pe2PhE&feature=youtu.be">strong opinion</a>.</p>
<h2 id="context">Context</h2>
<p>Let’s suppose that we have a <em>Product</em> Service which has an HTTP method that provides product information in a JSON
format upon receiving a product id:</p>
<p><code class="highlighter-rouge">HTTP GET: api/v1/product?id=123</code></p>
<pre><code class="language-JSON">{
"name": "nexus",
"type": "smartphone",
"price": "21.03"
}
</code></pre>
<p>The product information are consumed by <em>Customer</em> Service.</p>
<p><img src="/img/services-01.png" alt="producer-consumer" title="producer-consumer" /></p>
<p>Conventions are defined in this way:</p>
<ul>
<li><em>Customer</em> Service is the <em>Consumer</em></li>
<li><em>Product</em> Service is the <em>Provider</em></li>
</ul>
<p>During developing, the <em>Product</em> service can evolve the API in a way that the HTTP response change the data format.
For example, the <em>type</em> field from a string value change to object:</p>
<pre><code class="language-JSON">{
"name": "nexus",
"type": {
"category": "smartphone",
"weight": 0.2,
"color": "blue"
},
"price": "21.03"
}
</code></pre>
<p>this is defined as a <strong>breaking change</strong> in which <em>Provider</em> doesn’t respect the defined interaction between <em>Consumer</em>.</p>
<p>In the same way, the Customer service can evolve the request call. For example, instead of call the API with a query
parameter <code class="highlighter-rouge">id</code>, it can use a field in the header to query the Product Service. Also, this example is a <em>sort
of</em> <strong>breaking change</strong> in which <em>Consumer</em> doesn’t respect the defined interaction between <em>Provider</em>.</p>
<p>Therefore, the interaction between services can be broken in many ways, and the cause can be triggered by both
sides which makes necessary some checks to avoid regression during the development.</p>
<h2 id="e2e-testing">e2e Testing</h2>
<p>The <em>simplest</em> thing to do, is to create an <a href="https://martinfowler.com/articles/practical-test-pyramid.html#End-to-endTests">end-to-end test</a>
that cover the entire calls flow between <em>Consumer Service</em> and <em>Provider Service</em>.</p>
<p><img src="/img/services-02.png" alt="e2e" title="e2e" /></p>
<p>Despite what I previously said about <em>simplicity</em>, e2e testing give the best confidence on software behaviour but with some problems.
They are flaky tests and often fail with false positive furthermore e2e tests are hard do maintain, slow, and it’s necessary to
span multiple services in testing environment with terrible slowness caused by deploy flow and environment nightmares.
There are some solutions (<a href="https://www.soapui.org/">1</a>, <a href="https://github.com/postmanlabs/newman">2</a>) that can provide the
right balance between <em>simplicity</em> and <em>maintainability</em> which are a step back e2e tests but often you need a staging
environment to execute tests verification or add a level of complexity to remove the environment need, which
personally I found with these solutions a tedious process. Moreover, all these solutions are <em>reactive</em> approaches which
in the simplest case, doesn’t avoid the integration of code that breaks the services interactions, but they provide a sort
of alerting like open a Jira defect or github issue. It’s possible to avoid code integration in case of breaks but
imply an overcomplicated CI or some <a href="https://martinfowler.com/articles/branching-patterns.html#experimental-branch">experimental branch</a>.</p>
<h2 id="mocks">Mocks</h2>
<p><img src="https://media.giphy.com/media/26n6ziTEeDDbowBkQ/giphy.gif" alt="Fake news" /></p>
<p><del>Developers</del> (I) usually dislike maintaining things which depend on environments or that needs hours to have a result.
If something is faulty and slow, it’s often untrusted and consequently useless. Furthermore, works with other services
means deal with other teams which are often too much busy doing new <del>bugs</del> features. So then, to avoid this
annoying stuff, it’s necessary to adopt a strategy which imply a level of complexity which <em>usually</em> developers are used
to see: <strong>Mocks</strong>.</p>
<p>Mocks are a type of <em>TestDouble</em> that define a sort of specification
based on expectations and, in this particular case, mocks can substitute APIs or clients reducing in this way, parties
to set up and run.</p>
<p><img src="/img/services-03.png" alt="services with mocks" title="services with mocks" /></p>
<p>Even if the image show <em>deployed</em> services, there are many <a href="https://www.baeldung.com/spring-boot-testing#integration-testing-with-springboottest">solutions</a>
to load part of an application which doesn’t imply a real execution. however, you can simulate an interaction
through a <a href="https://martinfowler.com/articles/mocksArentStubs.html">mock or stub</a> based on <strong>Contracts</strong>. As showed before,
we can have two categories of breaking change based on the side that doesn’t maintain expectations and in the same way,
we can identify two categories of contracts:</p>
<ul>
<li>Provider Contracts</li>
<li>Consumer Contracts</li>
</ul>
<h3 id="contracts-characteristics">Contracts characteristics</h3>
<p>A <em>Provider</em> service exposes a set of business functionalities which can be <strong>used or not</strong> by one or many consumers
and ingested in different ways. A change in the provider interface can break interactions with many consumers, but it is
not the same for the consumer. In the same way, a Provider contract cover completely the functionalities exposed by
the service with only one definition. On the contrary, a Consumer contract can cover only a set of functionalities
that are interesting for the service.</p>
<h6><img src="/img/services-04_1.png" alt="consumer contracts" title="consumer contracts" /></h6>
<p>We can say that a provider contract is a <strong>closed</strong> and <strong>complete</strong> expression of business functionalities.
Instead, consumer contract is an <strong>open</strong> and <strong>incomplete</strong> definition of business expectations. When a provider
accepts the expectations defined by the consumer contract, confirms that the expectation is a functionality that supported
for a period of time.</p>
<h2 id="consumer-driven-contracts">Consumer-driven Contracts</h2>
<p><img src="/img/googlesearch.jpg" alt="google search true story" title="google search true story" /></p>
<p>Ok, so now? Well, If you take a look on internet, <a href="https://pactflow.io/blog/the-curious-case-for-the-provider-driven-contract"><del>you will not find</del></a>
any trace of provider driven contract testing <a href="https://github.com/DiUS/pact-jvm/issues/327"><del>or question about it</del></a>.
On the contrary, <a href="https://lmgtfy.com/?q=consumer+driven+contract+testing&s=d">the web is full of posts about Consumer-driven contract testing</a>.
This should be enough for you and me to choose a consumer-driven solution but, as I said at the beginning,
the idea of this post is to give the minimum set of knowledge about Contract testing, and to have an answer
in case of your colleagues are free mind enough to ask if exists an alternative meanwhile you are exposing why Contract
tests are so <a href="https://reflectoring.io/7-reasons-for-consumer-driven-contracts/">cool</a>.</p>
<p>In short terms, it’s all about business. Consumer contracts point the finger on current supported business value exposed
by the provider. In a consumer-driven approach, the sum of all contracts generated by the consumers
and asserted by the provider is <strong>closed</strong> and <strong>complete</strong> respect the functionalities requested.</p>
<p>Anyway Consumer-driven Contracts drive the evolution of the services keeping the focus on what really matter with
a feedback loop on the changes that will arrive during the life and death of the services which cannot be achievable
with a Provider-driven approach which not take in account the feedback from the consumer.</p>
<p>In my experience, it’s easier and natural to think in a Provider-First manner than Consumer-first, and the reason behind
this mindset, it might be connected to the fact that a breaking change made by the Provider is more detectable than the one
made by the Consumer. In a real world example where your team isn’t the owner of both services, you have to deal with meetings,
longer meetings and extravagant, informal, hermetic, long-winded design docs and other <a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month">mythical beasts</a>.
A contract is a formal expression of needs and duties which can be another tool in your pocket that can be used in order
to reduce the background noise during the process of evolution of services. Probably you know the sensation of powerlessness
when a design doc or <a href="https://www.openapis.org/">swagger definition</a> reaches the mailbox or a shared folder and it’s
necessary another meeting or mail tread to have a change in the definition or worse, get an HTTP response status error because
someone made a little change in the API which isn’t versioned.</p>
<p><img src="/img/services-07.png" alt="Consumer Driven Process" title="Consumer Driven Process" /></p>
<p>To summarize, Consumer-Driven contracts can give you a process that presents an iterative way of proceeding with a
formalised format which can help large organization with services which are owned by different teams that can be in different
locations.</p>
<h1 id="contract-testing-with-pact">Contract Testing with Pact</h1>
<p><a href="https://docs.pact.io/">Pact.io</a> is an implementation of Consumer-driven contract testing which actually support <a href="https://docs.pact.io/implementation_guides/other_languages">many
languages</a>. At the moment of writing this post,
pact foundation released <a href="https://github.com/pact-foundation/pact-specification">v3 specification</a> which cover the following
features:</p>
<ul>
<li>pact format for message queues</li>
<li>regular expression and type matching</li>
<li>specification shared between Ruby, JVM and .Net versions</li>
</ul>
<p><img src="/img/services-05_1.png" alt="Pact ecosystem" title="Pact ecosystem" /></p>
<p>Furthermore, it’s available a <a href="https://github.com/pact-foundation/pact_broker">broker</a> which can be used to publish
and share contracts between services.</p>
<h2 id="whats-next">What’s Next</h2>
<p>We have covered the minimum set of principles and motivations that are necessary in my opinion to work with
contract testing. In the next posts we will take a look to how:</p>
<ul>
<li>create consumer-driven contracts tests with Pact and Java</li>
<li>setup broker server</li>
<li>integration with Continuous Integration</li>
</ul>
<h2 id="references">References</h2>
<blockquote>
<ul>
<li><a href="https://martinfowler.com/articles/consumerDrivenContracts.html#Schematron">Consumer-Driven Contracts: A Service Evolution Pattern</a></li>
<li><a href="https://martinfowler.com/bliki/ContractTest.html">ContractTest</a></li>
<li><a href="https://martinfowler.com/bliki/TestDouble.html">TestDouble</a></li>
<li><a href="https://pactflow.io/blog/the-curious-case-for-the-provider-driven-contract">The curious case for the Provider Driven Contract</a></li>
<li><a href="https://martinfowler.com/articles/practical-test-pyramid.html">The Practical Test Pyramid</a></li>
<li><a href="https://martinfowler.com/articles/branching-patterns.html">Patterns for Managing Source COde Branches</a></li>
<li><a href="https://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren’t Stubs</a></li>
<li><a href="https://reflectoring.io/7-reasons-for-consumer-driven-contracts/">7 Reasons to Choose Consumer-Driven Contract Tests Over End-to-End Tests</a></li>
</ul>
</blockquote>nmosfIntroduction