1764 lines
70 KiB
HTML
1764 lines
70 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="generator" content="Asciidoctor 1.5.7.1">
|
|
<title>Spring Cloud Contract Verifier Setup</title>
|
|
<link rel="stylesheet" href="css/spring.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
|
|
<style>
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
|
|
.switch {
|
|
border-width: 1px 1px 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
display: inline-block;
|
|
}
|
|
|
|
.switch--item {
|
|
padding: 10px;
|
|
background-color: #ffffff;
|
|
color: #7a2518;
|
|
display: inline-block;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.switch--item:not(:first-child) {
|
|
border-width: 0 0 0 1px;
|
|
border-style: solid;
|
|
border-color: #7a2518;
|
|
}
|
|
|
|
.switch--item.selected {
|
|
background-color: #7a2519;
|
|
color: #ffffff;
|
|
}
|
|
</style>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
|
|
<script type="text/javascript">
|
|
function addBlockSwitches() {
|
|
$('.primary').each(function() {
|
|
primary = $(this);
|
|
createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected");
|
|
primary.children('.title').remove();
|
|
});
|
|
$('.secondary').each(function(idx, node) {
|
|
secondary = $(node);
|
|
primary = findPrimary(secondary);
|
|
switchItem = createSwitchItem(secondary, primary.children('.switch'));
|
|
switchItem.content.addClass('hidden');
|
|
findPrimary(secondary).append(switchItem.content);
|
|
secondary.remove();
|
|
});
|
|
}
|
|
|
|
function createBlockSwitch(primary) {
|
|
blockSwitch = $('<div class="switch"></div>');
|
|
primary.prepend(blockSwitch);
|
|
return blockSwitch;
|
|
}
|
|
|
|
function findPrimary(secondary) {
|
|
candidate = secondary.prev();
|
|
while (!candidate.is('.primary')) {
|
|
candidate = candidate.prev();
|
|
}
|
|
return candidate;
|
|
}
|
|
|
|
function createSwitchItem(block, blockSwitch) {
|
|
blockName = block.children('.title').text();
|
|
content = block.children('.content').first().append(block.next('.colist'));
|
|
item = $('<div class="switch--item">' + blockName + '</div>');
|
|
item.on('click', '', content, function(e) {
|
|
$(this).addClass('selected');
|
|
$(this).siblings().removeClass('selected');
|
|
e.data.siblings('.content').addClass('hidden');
|
|
e.data.removeClass('hidden');
|
|
});
|
|
blockSwitch.append(item);
|
|
return {'item': item, 'content': content};
|
|
}
|
|
|
|
$(addBlockSwitches);
|
|
</script>
|
|
|
|
</head>
|
|
<body class="book toc2 toc-left">
|
|
<div id="header">
|
|
<div id="toc" class="toc2">
|
|
<div id="toctitle">Table of Contents</div>
|
|
<ul class="sectlevel1">
|
|
<li><a href="#_spring_cloud_contract_verifier_setup">Spring Cloud Contract Verifier Setup</a>
|
|
<ul class="sectlevel2">
|
|
<li><a href="#gradle-project">Gradle Project</a></li>
|
|
<li><a href="#maven-project">Maven Project</a></li>
|
|
<li><a href="#_stubs_and_transitive_dependencies">Stubs and Transitive Dependencies</a></li>
|
|
<li><a href="#_scenarios">Scenarios</a></li>
|
|
<li><a href="#docker-project">Docker Project</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div id="content">
|
|
<div class="sect1">
|
|
<h2 id="_spring_cloud_contract_verifier_setup"><a class="link" href="#_spring_cloud_contract_verifier_setup">Spring Cloud Contract Verifier Setup</a></h2>
|
|
<div class="sectionbody">
|
|
<div class="paragraph">
|
|
<p>You can set up Spring Cloud Contract Verifier in the following ways:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#gradle-project">As a Gradle project</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-project">As a Maven project</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#docker-project">As a Docker project</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="gradle-project"><a class="link" href="#gradle-project">Gradle Project</a></h3>
|
|
<div class="paragraph">
|
|
<p>To learn how to set up the Gradle project for Spring Cloud Contract Verifier, read the
|
|
following sections:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#gradle-prerequisites">Prerequisites</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-add-gradle-plugin">Add Gradle Plugin with Dependencies</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-and-rest-assured">Gradle and Rest Assured 2.0</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-snapshot-versions">Snapshot Versions for Gradle</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-add-stubs">Add stubs</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-default-setup">Default Setup</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-configure-plugin">Configure Plugin</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-configuration-options">Configuration Options</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-single-base-class">Single Base Class for All Tests</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-different-base-classes">Different Base Classes for Contracts</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-invoking-generated-tests">Invoking Generated Tests</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-pushing-stubs-to-scm">Pushing stubs to SCM</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#gradle-consumer">Spring Cloud Contract Verifier on the Consumer Side</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-prerequisites"><a class="link" href="#gradle-prerequisites">Prerequisites</a></h4>
|
|
<div class="paragraph">
|
|
<p>In order to use Spring Cloud Contract Verifier with WireMock, you muse use either a
|
|
Gradle or a Maven plugin.</p>
|
|
</div>
|
|
<div class="admonitionblock warning">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-warning" title="Warning"></i>
|
|
</td>
|
|
<td class="content">
|
|
If you want to use Spock in your projects, you must add separately the
|
|
<code>spock-core</code> and <code>spock-spring</code> modules. Check <a href="https://spockframework.github.io/">Spock
|
|
docs for more information</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-add-gradle-plugin"><a class="link" href="#gradle-add-gradle-plugin">Add Gradle Plugin with Dependencies</a></h4>
|
|
<div class="paragraph">
|
|
<p>To add a Gradle plugin with dependencies, use code similar to this:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">buildscript {
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
dependencies {
|
|
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
|
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
|
}
|
|
}
|
|
|
|
apply plugin: 'groovy'
|
|
apply plugin: 'spring-cloud-contract'
|
|
|
|
dependencyManagement {
|
|
imports {
|
|
mavenBom "org.springframework.cloud:spring-cloud-contract-dependencies:${verifier_version}"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
testCompile 'org.codehaus.groovy:groovy-all:2.4.6'
|
|
// example with adding Spock core and Spock Spring
|
|
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
|
|
testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
|
|
testCompile 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-and-rest-assured"><a class="link" href="#gradle-and-rest-assured">Gradle and Rest Assured 2.0</a></h4>
|
|
<div class="paragraph">
|
|
<p>By default, Rest Assured 3.x is added to the classpath. However, to use Rest Assured 2.x
|
|
you can add it to the plugins classpath, as shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">buildscript {
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
dependencies {
|
|
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
|
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
|
|
classpath "com.jayway.restassured:rest-assured:2.5.0"
|
|
classpath "com.jayway.restassured:spring-mock-mvc:2.5.0"
|
|
}
|
|
}
|
|
|
|
depenendencies {
|
|
// all dependencies
|
|
// you can exclude rest-assured from spring-cloud-contract-verifier
|
|
testCompile "com.jayway.restassured:rest-assured:2.5.0"
|
|
testCompile "com.jayway.restassured:spring-mock-mvc:2.5.0"
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>That way, the plugin automatically sees that Rest Assured 2.x is present on the classpath
|
|
and modifies the imports accordingly.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-snapshot-versions"><a class="link" href="#gradle-snapshot-versions">Snapshot Versions for Gradle</a></h4>
|
|
<div class="paragraph">
|
|
<p>Add the additional snapshot repository to your build.gradle to use snapshot versions,
|
|
which are automatically uploaded after every successful build, as shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-add-stubs"><a class="link" href="#gradle-add-stubs">Add stubs</a></h4>
|
|
<div class="paragraph">
|
|
<p>By default, Spring Cloud Contract Verifier is looking for stubs in the
|
|
<code>src/test/resources/contracts</code> directory.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The directory containing stub definitions is treated as a class name, and each stub
|
|
definition is treated as a single test. Spring Cloud Contract Verifier assumes that it
|
|
contains at least one level of directories that are to be used as the test class name.
|
|
If more than one level of nested directories is present, all except the last one is used
|
|
as the package name. For example, with following structure:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">src/test/resources/contracts/myservice/shouldCreateUser.groovy
|
|
src/test/resources/contracts/myservice/shouldReturnUser.groovy</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Spring Cloud Contract Verifier creates a test class named <code>defaultBasePackage.MyService</code>
|
|
with two methods:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>shouldCreateUser()</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>shouldReturnUser()</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-run-plugin"><a class="link" href="#gradle-run-plugin">Run the Plugin</a></h4>
|
|
<div class="paragraph">
|
|
<p>The plugin registers itself to be invoked before a <code>check</code> task. If you want it to be
|
|
part of your build process, you need to do nothing more. If you just want to generate
|
|
tests, invoke the <code>generateContractTests</code> task.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-default-setup"><a class="link" href="#gradle-default-setup">Default Setup</a></h4>
|
|
<div class="paragraph">
|
|
<p>The default Gradle Plugin setup creates the following Gradle part of the build (in
|
|
pseudocode):</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">contracts {
|
|
testFramework ='JUNIT'
|
|
testMode = 'MockMvc'
|
|
generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/contracts")
|
|
generatedTestResourcesDir = project.file("${project.buildDir}/generated-test-resources/contracts")
|
|
contractsDslDir = "${project.rootDir}/src/test/resources/contracts"
|
|
basePackageForTests = 'org.springframework.cloud.verifier.tests'
|
|
stubsOutputDir = project.file("${project.buildDir}/stubs")
|
|
|
|
// the following properties are used when you want to provide where the JAR with contract lays
|
|
contractDependency {
|
|
stringNotation = ''
|
|
}
|
|
contractsPath = ''
|
|
contractsWorkOffline = false
|
|
contractRepository {
|
|
cacheDownloadedContracts(true)
|
|
}
|
|
}
|
|
|
|
tasks.create(type: Jar, name: 'verifierStubsJar', dependsOn: 'generateClientStubs') {
|
|
baseName = project.name
|
|
classifier = contracts.stubsSuffix
|
|
from contractVerifier.stubsOutputDir
|
|
}
|
|
|
|
project.artifacts {
|
|
archives task
|
|
}
|
|
|
|
tasks.create(type: Copy, name: 'copyContracts') {
|
|
from contracts.contractsDslDir
|
|
into contracts.stubsOutputDir
|
|
}
|
|
|
|
verifierStubsJar.dependsOn 'copyContracts'
|
|
|
|
publishing {
|
|
publications {
|
|
stubs(MavenPublication) {
|
|
artifactId project.name
|
|
artifact verifierStubsJar
|
|
}
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-configure-plugin"><a class="link" href="#gradle-configure-plugin">Configure Plugin</a></h4>
|
|
<div class="paragraph">
|
|
<p>To change the default configuration, add a <code>contracts</code> snippet to your Gradle config, as
|
|
shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">contracts {
|
|
testMode = 'MockMvc'
|
|
baseClassForTests = 'org.mycompany.tests'
|
|
generatedTestSourcesDir = project.file('src/generatedContract')
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-configuration-options"><a class="link" href="#gradle-configuration-options">Configuration Options</a></h4>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>testMode</strong>: Defines the mode for acceptance tests. By default, the mode is MockMvc,
|
|
which is based on Spring’s MockMvc. It can also be changed to <strong>WebTestClient</strong>, <strong>JaxRsClient</strong> or to
|
|
<strong>Explicit</strong> for real HTTP calls.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>imports</strong>: Creates an array with imports that should be included in generated tests
|
|
(for example ['org.myorg.Matchers']). By default, it creates an empty array.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>staticImports</strong>: Creates an array with static imports that should be included in
|
|
generated tests(for example ['org.myorg.Matchers.*']). By default, it creates an empty
|
|
array.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>basePackageForTests</strong>: Specifies the base package for all generated tests. If not set,
|
|
the value is picked from <code>baseClassForTests’s package and from `packageWithBaseClasses</code>.
|
|
If neither of these values are set, then the value is set to
|
|
<code>org.springframework.cloud.contract.verifier.tests</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>baseClassForTests</strong>: Creates a base class for all generated tests. By default, if you
|
|
use Spock classes, the class is <code>spock.lang.Specification</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>packageWithBaseClasses</strong>: Defines a package where all the base classes reside. This
|
|
setting takes precedence over <strong>baseClassForTests</strong>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>baseClassMappings</strong>: Explicitly maps a contract package to a FQN of a base class. This
|
|
setting takes precedence over <strong>packageWithBaseClasses</strong> and <strong>baseClassForTests</strong>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>ruleClassForTests</strong>: Specifies a rule that should be added to the generated test
|
|
classes.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>ignoredFiles</strong>: Uses an <code>Antmatcher</code> to allow defining stub files for which processing
|
|
should be skipped. By default, it is an empty array.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsDslDir</strong>: Specifies the directory containing contracts written using the
|
|
GroovyDSL. By default, its value is <code>$rootDir/src/test/resources/contracts</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>generatedTestSourcesDir</strong>: Specifies the test source directory where tests generated
|
|
from the Groovy DSL should be placed. By default its value is
|
|
<code>$buildDir/generated-test-sources/contracts</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>generatedTestResourcesDir</strong>: Specifies the test resource directory where resources used by the tests generated
|
|
from the Groovy DSL should be placed. By default its value is
|
|
<code>$buildDir/generated-test-resources/contracts</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>stubsOutputDir</strong>: Specifies the directory where the generated WireMock stubs from
|
|
the Groovy DSL should be placed.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>testFramework</strong>: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (<code>TestFramework.JUNIT</code>), TestNG and
|
|
JUnit 5 are supported with JUnit 4 being the default framework.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsProperties</strong>: a map containing properties to be passed to Spring Cloud Contract
|
|
components. Those properties might be used by e.g. inbuilt or custom Stub Downloaders.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The following properties are used when you want to specify the location of the JAR
|
|
containing the contracts:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>contractDependency</strong>: Specifies the Dependency that provides
|
|
<code>groupid:artifactid:version:classifier</code> coordinates. You can use the <code>contractDependency</code>
|
|
closure to set it up.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsPath</strong>: Specifies the path to the jar. If contract dependencies are
|
|
downloaded, the path defaults to <code>groupid/artifactid</code> where <code>groupid</code> is slash
|
|
separated. Otherwise, it scans contracts under the provided directory.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsMode</strong>: Specifies the mode of downloading contracts (whether the
|
|
JAR is available offline, remotely etc.)</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>deleteStubsAfterTest</strong>: If set to <code>false</code> will not remove any downloaded
|
|
contracts from temporary directories</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Below you can find a list of experimental features you can turn on via the plugin:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>convertToYaml</strong>: converts all DSLs to the declarative, YAML format. This can be extremely useful when you’re using external libraries in your Groovy DSLs. By turning this feature on (by setting it to <code>true</code>) you will not need to add the library dependency on the consumer side.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>assertJsonSize</strong>: You can check the size of JSON arrays in the generated tests. This feature is disabled by default.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-single-base-class"><a class="link" href="#gradle-single-base-class">Single Base Class for All Tests</a></h4>
|
|
<div class="paragraph">
|
|
<p>When using Spring Cloud Contract Verifier in default MockMvc, you need to create a base
|
|
specification for all generated acceptance tests. In this class, you need to point to an
|
|
endpoint, which should be verified.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you use <code>Explicit</code> mode, you can use a base class to initialize the whole tested app
|
|
as you might see in regular integration tests. If you use the <code>JAXRSCLIENT</code> mode, this
|
|
base class should also contain a <code>protected WebTarget webTarget</code> field. Right now, the
|
|
only option to test the JAX-RS API is to start a web server.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-different-base-classes"><a class="link" href="#gradle-different-base-classes">Different Base Classes for Contracts</a></h4>
|
|
<div class="paragraph">
|
|
<p>If your base classes differ between contracts, you can tell the Spring Cloud Contract
|
|
plugin which class should get extended by the autogenerated tests. You have two options:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Follow a convention by providing the <code>packageWithBaseClasses</code></p>
|
|
</li>
|
|
<li>
|
|
<p>Provide explicit mapping via <code>baseClassMappings</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>By Convention</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The convention is such that if you have a contract under (for example)
|
|
<code>src/test/resources/contract/foo/bar/baz/</code> and set the value of the
|
|
<code>packageWithBaseClasses</code> property to <code>com.example.base</code>, then Spring Cloud Contract
|
|
Verifier assumes that there is a <code>BarBazBase</code> class under the <code>com.example.base</code> package.
|
|
In other words, the system takes the last two parts of the package, if they exist, and
|
|
forms a class with a <code>Base</code> suffix. This rule takes precedence over <strong>baseClassForTests</strong>.
|
|
Here is an example of how it works in the <code>contracts</code> closure:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>By Mapping</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You can manually map a regular expression of the contract’s package to fully qualified
|
|
name of the base class for the matched contract. You have to provide a list called
|
|
<code>baseClassMappings</code> that consists <code>baseClassMapping</code> objects that takes a
|
|
<code>contractPackageRegex</code> to <code>baseClassFQN</code> mapping. Consider the following example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Let’s assume that you have contracts under
|
|
- <code>src/test/resources/contract/com/</code>
|
|
- <code>src/test/resources/contract/foo/</code></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>By providing the <code>baseClassForTests</code>, we have a fallback in case mapping did not succeed.
|
|
(You could also provide the <code>packageWithBaseClasses</code> as a fallback.) That way, the tests
|
|
generated from <code>src/test/resources/contract/com/</code> contracts extend the
|
|
<code>com.example.ComBase</code>, whereas the rest of the tests extend <code>com.example.FooBase</code>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-invoking-generated-tests"><a class="link" href="#gradle-invoking-generated-tests">Invoking Generated Tests</a></h4>
|
|
<div class="paragraph">
|
|
<p>To ensure that the provider side is compliant with defined contracts, you need to invoke:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./gradlew generateContractTests test</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-pushing-stubs-to-scm"><a class="link" href="#gradle-pushing-stubs-to-scm">Pushing stubs to SCM</a></h4>
|
|
<div class="paragraph">
|
|
<p>If you’re using the SCM repository to keep the contracts and
|
|
stubs, you might want to automate the step of pushing stubs to
|
|
the repository. To do that, it’s enough to call the <code>pushStubsToScm</code>
|
|
task. Example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./gradlew pushStubsToScm</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Under <a href="#scm-stub-downloader">[scm-stub-downloader]</a> you can find all possible
|
|
configuration options that you can pass either via
|
|
the <code>contractsProperties</code> field e.g. <code>contracts { contractsProperties = [foo:"bar"] }</code>,
|
|
via <code>contractsProperties</code> method e.g. <code>contracts { contractsProperties([foo:"bar"]) }</code>,
|
|
a system property or an environment variable.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="gradle-consumer"><a class="link" href="#gradle-consumer">Spring Cloud Contract Verifier on the Consumer Side</a></h4>
|
|
<div class="paragraph">
|
|
<p>In a consuming service, you need to configure the Spring Cloud Contract Verifier plugin
|
|
in exactly the same way as in case of provider. If you do not want to use Stub Runner
|
|
then you need to copy contracts stored in <code>src/test/resources/contracts</code> and generate
|
|
WireMock JSON stubs using:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./gradlew generateClientStubs</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="admonitionblock note">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-note" title="Note"></i>
|
|
</td>
|
|
<td class="content">
|
|
The <code>stubsOutputDir</code> option has to be set for stub generation to work.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When present, JSON stubs can be used in automated tests of consuming a service.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">@ContextConfiguration(loader == SpringApplicationContextLoader, classes == Application)
|
|
class LoanApplicationServiceSpec extends Specification {
|
|
|
|
@ClassRule
|
|
@Shared
|
|
WireMockClassRule wireMockRule == new WireMockClassRule()
|
|
|
|
@Autowired
|
|
LoanApplicationService sut
|
|
|
|
def 'should successfully apply for loan'() {
|
|
given:
|
|
LoanApplication application =
|
|
new LoanApplication(client: new Client(clientPesel: '12345678901'), amount: 123.123)
|
|
when:
|
|
LoanApplicationResult loanApplication == sut.loanApplication(application)
|
|
then:
|
|
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
|
|
loanApplication.rejectionReason == null
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><code>LoanApplication</code> makes a call to <code>FraudDetection</code> service. This request is handled by a
|
|
WireMock server configured with stubs generated by Spring Cloud Contract Verifier.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="maven-project"><a class="link" href="#maven-project">Maven Project</a></h3>
|
|
<div class="paragraph">
|
|
<p>To learn how to set up the Maven project for Spring Cloud Contract Verifier, read the
|
|
following sections:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><a href="#maven-add-plugin">Add maven plugin</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-rest-assured">Maven and Rest Assured 2.0</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-snapshot-versions">Snapshot versions for Maven</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-add-stubs">Add stubs</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-run-plugin">Run plugin</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-configure-plugin">Configure plugin</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-configuration-options">Configuration Options</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-single-base">Single Base Class for All Tests</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-different-base">Different base classes for contracts</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-invoking-generated-tests">Invoking generated tests</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-pushing-stubs-to-scm">Pushing stubs to SCM</a></p>
|
|
</li>
|
|
<li>
|
|
<p><a href="#maven-sts">Maven Plugin and STS</a></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-add-plugin"><a class="link" href="#maven-add-plugin">Add maven plugin</a></h4>
|
|
<div class="paragraph">
|
|
<p>Add the Spring Cloud Contract BOM in a fashion similar to this:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Next, add the <code>Spring Cloud Contract Verifier</code> Maven plugin:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You can read more in the
|
|
<a href="https://cloud.spring.io/spring-cloud-static/spring-cloud-contract/2.0.0.RELEASE/spring-cloud-contract-maven-plugin/">Spring
|
|
Cloud Contract Maven Plugin Documentation (example for <code>2.0.0.RELEASE</code> version)</a>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-rest-assured"><a class="link" href="#maven-rest-assured">Maven and Rest Assured 2.0</a></h4>
|
|
<div class="paragraph">
|
|
<p>By default, Rest Assured 3.x is added to the classpath. However, you can use Rest
|
|
Assured 2.x by adding it to the plugins classpath, as shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy"><plugin>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
|
<version>${spring-cloud-contract.version}</version>
|
|
<extensions>true</extensions>
|
|
<configuration>
|
|
<packageWithBaseClasses>com.example</packageWithBaseClasses>
|
|
</configuration>
|
|
<dependencies>
|
|
<dependency>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-contract-verifier</artifactId>
|
|
<version>${spring-cloud-contract.version}</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.jayway.restassured</groupId>
|
|
<artifactId>rest-assured</artifactId>
|
|
<version>2.5.0</version>
|
|
<scope>compile</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.jayway.restassured</groupId>
|
|
<artifactId>spring-mock-mvc</artifactId>
|
|
<version>2.5.0</version>
|
|
<scope>compile</scope>
|
|
</dependency>
|
|
</dependencies>
|
|
</plugin>
|
|
|
|
<dependencies>
|
|
<!-- all dependencies -->
|
|
<!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
|
|
<dependency>
|
|
<groupId>com.jayway.restassured</groupId>
|
|
<artifactId>rest-assured</artifactId>
|
|
<version>2.5.0</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>com.jayway.restassured</groupId>
|
|
<artifactId>spring-mock-mvc</artifactId>
|
|
<version>2.5.0</version>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
</dependencies></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>That way, the plugin automatically sees that Rest Assured 3.x is present on the classpath
|
|
and modifies the imports accordingly.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-snapshot-versions"><a class="link" href="#maven-snapshot-versions">Snapshot versions for Maven</a></h4>
|
|
<div class="paragraph">
|
|
<p>For Snapshot and Milestone versions, you have to add the following section to your
|
|
<code>pom.xml</code>, as shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-add-stubs"><a class="link" href="#maven-add-stubs">Add stubs</a></h4>
|
|
<div class="paragraph">
|
|
<p>By default, Spring Cloud Contract Verifier is looking for stubs in the
|
|
<code>src/test/resources/contracts</code> directory. The directory containing stub definitions is
|
|
treated as a class name, and each stub definition is treated as a single test. We assume
|
|
that it contains at least one directory to be used as test class name. If there is more
|
|
than one level of nested directories, all except the last one is used as package name.
|
|
For example, with following structure:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">src/test/resources/contracts/myservice/shouldCreateUser.groovy
|
|
src/test/resources/contracts/myservice/shouldReturnUser.groovy</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Spring Cloud Contract Verifier creates a test class named <code>defaultBasePackage.MyService</code>
|
|
with two methods</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>shouldCreateUser()</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>shouldReturnUser()</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-run-plugin"><a class="link" href="#maven-run-plugin">Run plugin</a></h4>
|
|
<div class="paragraph">
|
|
<p>The plugin goal <code>generateTests</code> is assigned to be invoked in the phase called
|
|
<code>generate-test-sources</code>. If you want it to be part of your build process, you need not do
|
|
anything. If you just want to generate tests, invoke the <code>generateTests</code> goal.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-configure-plugin"><a class="link" href="#maven-configure-plugin">Configure plugin</a></h4>
|
|
<div class="paragraph">
|
|
<p>To change the default configuration, just add a <code>configuration</code> section to the plugin
|
|
definition or the <code>execution</code> definition, as shown here:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><plugin>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
|
<executions>
|
|
<execution>
|
|
<goals>
|
|
<goal>convert</goal>
|
|
<goal>generateStubs</goal>
|
|
<goal>generateTests</goal>
|
|
</goals>
|
|
</execution>
|
|
</executions>
|
|
<configuration>
|
|
<basePackageForTests>org.springframework.cloud.verifier.twitter.place</basePackageForTests>
|
|
<baseClassForTests>org.springframework.cloud.verifier.twitter.place.BaseMockMvcSpec</baseClassForTests>
|
|
</configuration>
|
|
</plugin></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-configuration-options"><a class="link" href="#maven-configuration-options">Configuration Options</a></h4>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>testMode</strong>: Defines the mode for acceptance tests. By default, the mode is MockMvc,
|
|
which is based on Spring’s MockMvc. It can also be changed to <strong>WebTestClient</strong>, <strong>JaxRsClient</strong> or to
|
|
<strong>Explicit</strong> for real HTTP calls.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>basePackageForTests</strong>: Specifies the base package for all generated tests. If not set,
|
|
the value is picked from <code>baseClassForTests’s package and from `packageWithBaseClasses</code>.
|
|
If neither of these values are set, then the value is set to
|
|
<code>org.springframework.cloud.contract.verifier.tests</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>ruleClassForTests</strong>: Specifies a rule that should be added to the generated test
|
|
classes.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>baseClassForTests</strong>: Creates a base class for all generated tests. By default, if you
|
|
use Spock classes, the class is <code>spock.lang.Specification</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsDirectory</strong>: Specifies a directory containing contracts written with the
|
|
GroovyDSL. The default directory is <code>/src/test/resources/contracts</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>generatedTestSourcesDir</strong>: Specifies the test source directory where tests generated
|
|
from the Groovy DSL should be placed. By default its value is
|
|
<code>$buildDir/generated-test-sources/contracts</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>generatedTestResourcesDir</strong>: Specifies the test resource directory where resources used by the tests generated</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>testFramework</strong>: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (<code>TestFramework.JUNIT</code>) and
|
|
JUnit 5 are supported with JUnit 4 being the default framework.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>packageWithBaseClasses</strong>: Defines a package where all the base classes reside. This
|
|
setting takes precedence over <strong>baseClassForTests</strong>. The convention is such that, if you
|
|
have a contract under (for example) <code>src/test/resources/contract/foo/bar/baz/</code> and set
|
|
the value of the <code>packageWithBaseClasses</code> property to <code>com.example.base</code>, then Spring
|
|
Cloud Contract Verifier assumes that there is a <code>BarBazBase</code> class under the
|
|
<code>com.example.base</code> package. In other words, the system takes the last two parts of the
|
|
package, if they exist, and forms a class with a <code>Base</code> suffix.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>baseClassMappings</strong>: Specifies a list of base class mappings that provide
|
|
<code>contractPackageRegex</code>, which is checked against the package where the contract is
|
|
located, and <code>baseClassFQN</code>, which maps to the fully qualified name of the base class for
|
|
the matched contract. For example, if you have a contract under
|
|
<code>src/test/resources/contract/foo/bar/baz/</code> and map the property
|
|
<code>.* → com.example.base.BaseClass</code>, then the test class generated from these contracts
|
|
extends <code>com.example.base.BaseClass</code>. This setting takes precedence over
|
|
<strong>packageWithBaseClasses</strong> and <strong>baseClassForTests</strong>.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsProperties</strong>: a map containing properties to be passed to Spring Cloud Contract
|
|
components. Those properties might be used by e.g. inbuilt or custom Stub Downloaders.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you want to download your contract definitions from a Maven repository, you can use
|
|
the following options:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>contractDependency</strong>: The contract dependency that contains all the packaged contracts.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsPath</strong>: The path to the concrete contracts in the JAR with packaged contracts.
|
|
Defaults to <code>groupid/artifactid</code> where <code>gropuid</code> is slash separated.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsMode</strong>: Picks the mode in which stubs will be found and registered</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>deleteStubsAfterTest</strong>: If set to <code>false</code> will not remove any downloaded
|
|
contracts from temporary directories</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsRepositoryUrl</strong>: URL to a repo with the artifacts that have contracts. If it is not provided,
|
|
use the current Maven ones.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsRepositoryUsername</strong>: The user name to be used to connect to the repo with contracts.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsRepositoryPassword</strong>: The password to be used to connect to the repo with contracts.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsRepositoryProxyHost</strong>: The proxy host to be used to connect to the repo with contracts.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>contractsRepositoryProxyPort</strong>: The proxy port to be used to connect to the repo with contracts.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>We cache only non-snapshot, explicitly provided versions (for example
|
|
<code>+</code> or <code>1.0.0.BUILD-SNAPSHOT</code> won’t get cached). By default, this feature is turned on.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Below you can find a list of experimental features you can turn on via the plugin:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><strong>convertToYaml</strong>: converts all DSLs to the declarative, YAML format. This can be extremely useful when you’re using external libraries in your Groovy DSLs. By turning this feature on (by setting it to <code>true</code>) you will not need to add the library dependency on the consumer side.</p>
|
|
</li>
|
|
<li>
|
|
<p><strong>assertJsonSize</strong>: You can check the size of JSON arrays in the generated tests. This feature is disabled by default.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-single-base"><a class="link" href="#maven-single-base">Single Base Class for All Tests</a></h4>
|
|
<div class="paragraph">
|
|
<p>When using Spring Cloud Contract Verifier in default MockMvc, you need to create a base
|
|
specification for all generated acceptance tests. In this class, you need to point to an
|
|
endpoint, which should be verified.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-groovy hljs" data-lang="groovy">package org.mycompany.tests
|
|
|
|
import org.mycompany.ExampleSpringController
|
|
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc
|
|
import spock.lang.Specification
|
|
|
|
class MvcSpec extends Specification {
|
|
def setup() {
|
|
RestAssuredMockMvc.standaloneSetup(new ExampleSpringController())
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You can also setup the whole context if necessary.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
|
import org.junit.Before;
|
|
import org.junit.runner.RunWith;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.test.context.junit4.SpringRunner;
|
|
import org.springframework.web.context.WebApplicationContext;
|
|
|
|
@RunWith(SpringRunner.class)
|
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
|
|
public abstract class BaseTestClass {
|
|
|
|
@Autowired
|
|
WebApplicationContext context;
|
|
|
|
@Before
|
|
public void setup() {
|
|
RestAssuredMockMvc.webAppContextSetup(this.context);
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you use <code>EXPLICIT</code> mode, you can use a base class to initialize the whole tested app
|
|
similarly, as you might find in regular integration tests.</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import io.restassured.RestAssured;
|
|
import org.junit.Before;
|
|
import org.junit.runner.RunWith;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.boot.web.server.LocalServerPort
|
|
import org.springframework.test.context.junit4.SpringRunner;
|
|
import org.springframework.web.context.WebApplicationContext;
|
|
|
|
@RunWith(SpringRunner.class)
|
|
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = SomeConfig.class, properties="some=property")
|
|
public abstract class BaseTestClass {
|
|
|
|
@LocalServerPort
|
|
int port;
|
|
|
|
@Before
|
|
public void setup() {
|
|
RestAssured.baseURI = "http://localhost:" + this.port;
|
|
}
|
|
}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you use the <code>JAXRSCLIENT</code> mode, this base class should also contain a <code>protected WebTarget webTarget</code> field. Right
|
|
now, the only option to test the JAX-RS API is to start a web server.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-different-base"><a class="link" href="#maven-different-base">Different base classes for contracts</a></h4>
|
|
<div class="paragraph">
|
|
<p>If your base classes differ between contracts, you can tell the Spring Cloud Contract
|
|
plugin which class should get extended by the autogenerated tests. You have two options:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Follow a convention by providing the <code>packageWithBaseClasses</code></p>
|
|
</li>
|
|
<li>
|
|
<p>provide explicit mapping via <code>baseClassMappings</code></p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>By Convention</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The convention is such that if you have a contract under (for example)
|
|
<code>src/test/resources/contract/foo/bar/baz/</code> and set the value of the
|
|
<code>packageWithBaseClasses</code> property to <code>com.example.base</code>, then Spring Cloud Contract
|
|
Verifier assumes that there is a <code>BarBazBase</code> class under the <code>com.example.base</code> package.
|
|
In other words, the system takes the last two parts of the package, if they exist, and
|
|
forms a class with a <code>Base</code> suffix. This rule takes precedence over <strong>baseClassForTests</strong>.
|
|
Here is an example of how it works in the <code>contracts</code> closure:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>By Mapping</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>You can manually map a regular expression of the contract’s package to fully qualified
|
|
name of the base class for the matched contract. You have to provide a list called
|
|
<code>baseClassMappings</code> that consists <code>baseClassMapping</code> objects that takes a
|
|
<code>contractPackageRegex</code> to <code>baseClassFQN</code> mapping. Consider the following example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Assume that you have contracts under these two locations:
|
|
* <code>src/test/resources/contract/com/</code>
|
|
* <code>src/test/resources/contract/foo/</code></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>By providing the <code>baseClassForTests</code>, we have a fallback in case mapping did not succeed.
|
|
(You can also provide the <code>packageWithBaseClasses</code> as a fallback.) That way, the tests
|
|
generated from <code>src/test/resources/contract/com/</code> contracts extend the
|
|
<code>com.example.ComBase</code>, whereas the rest of the tests extend <code>com.example.FooBase</code>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-invoking-generated-tests"><a class="link" href="#maven-invoking-generated-tests">Invoking generated tests</a></h4>
|
|
<div class="paragraph">
|
|
<p>The Spring Cloud Contract Maven Plugin generates verification code in a directory called
|
|
<code>/generated-test-sources/contractVerifier</code> and attaches this directory to <code>testCompile</code>
|
|
goal.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>For Groovy Spock code, use the following:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><plugin>
|
|
<groupId>org.codehaus.gmavenplus</groupId>
|
|
<artifactId>gmavenplus-plugin</artifactId>
|
|
<version>1.5</version>
|
|
<executions>
|
|
<execution>
|
|
<goals>
|
|
<goal>testCompile</goal>
|
|
</goals>
|
|
</execution>
|
|
</executions>
|
|
<configuration>
|
|
<testSources>
|
|
<testSource>
|
|
<directory>${project.basedir}/src/test/groovy</directory>
|
|
<includes>
|
|
<include>**/*.groovy</include>
|
|
</includes>
|
|
</testSource>
|
|
<testSource>
|
|
<directory>${project.build.directory}/generated-test-sources/contractVerifier</directory>
|
|
<includes>
|
|
<include>**/*.groovy</include>
|
|
</includes>
|
|
</testSource>
|
|
</testSources>
|
|
</configuration>
|
|
</plugin></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To ensure that provider side is compliant with defined contracts, you need to invoke
|
|
<code>mvn generateTest test</code>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-pushing-stubs-to-scm"><a class="link" href="#maven-pushing-stubs-to-scm">Pushing stubs to SCM</a></h4>
|
|
<div class="paragraph">
|
|
<p>If you’re using the SCM repository to keep the contracts and
|
|
stubs, you might want to automate the step of pushing stubs to
|
|
the repository. To do that, it’s enough to add the <code>pushStubsToScm</code>
|
|
goal. Example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><plugin>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
|
<version>${spring-cloud-contract.version}</version>
|
|
<extensions>true</extensions>
|
|
<configuration>
|
|
<!-- Base class mappings etc. -->
|
|
|
|
<!-- We want to pick contracts from a Git repository -->
|
|
<contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs-contracts-git.git</contractsRepositoryUrl>
|
|
|
|
<!-- We reuse the contract dependency section to set up the path
|
|
to the folder that contains the contract definitions. In our case the
|
|
path will be /groupId/artifactId/version/contracts -->
|
|
<contractDependency>
|
|
<groupId>${project.groupId}</groupId>
|
|
<artifactId>${project.artifactId}</artifactId>
|
|
<version>${project.version}</version>
|
|
</contractDependency>
|
|
|
|
<!-- The contracts mode can't be classpath -->
|
|
<contractsMode>REMOTE</contractsMode>
|
|
</configuration>
|
|
<executions>
|
|
<execution>
|
|
<phase>package</phase>
|
|
<goals>
|
|
<!-- By default we will not push the stubs back to SCM,
|
|
you have to explicitly add it as a goal -->
|
|
<goal>pushStubsToScm</goal>
|
|
</goals>
|
|
</execution>
|
|
</executions>
|
|
</plugin></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Under <a href="#scm-stub-downloader">[scm-stub-downloader]</a> you can find all possible
|
|
configuration options that you can pass either via
|
|
the <code><configuration><contractProperties></code> map, a system property
|
|
or an environment variable.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="maven-sts"><a class="link" href="#maven-sts">Maven Plugin and STS</a></h4>
|
|
<div class="paragraph">
|
|
<p>If you see the following exception while using STS:</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>When you click on the error marker you should see something like this:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash"> plugin:1.1.0.M1:convert:default-convert:process-test-resources) org.apache.maven.plugin.PluginExecutionException: Execution default-convert of goal org.springframework.cloud:spring-
|
|
cloud-contract-maven-plugin:1.1.0.M1:convert failed. at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145) at
|
|
org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331) at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362) at
|
|
...
|
|
org.eclipse.core.internal.jobs.Worker.run(Worker.java:55) Caused by: java.lang.NullPointerException at
|
|
org.eclipse.m2e.core.internal.builder.plexusbuildapi.EclipseIncrementalBuildContext.hasDelta(EclipseIncrementalBuildContext.java:53) at
|
|
org.sonatype.plexus.build.incremental.ThreadBuildContext.hasDelta(ThreadBuildContext.java:59) at</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>In order to fix this issue, provide the following section in your <code>pom.xml</code>:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><build>
|
|
<pluginManagement>
|
|
<plugins>
|
|
<!--This plugin's configuration is used to store Eclipse m2e settings
|
|
only. It has no influence on the Maven build itself. -->
|
|
<plugin>
|
|
<groupId>org.eclipse.m2e</groupId>
|
|
<artifactId>lifecycle-mapping</artifactId>
|
|
<version>1.0.0</version>
|
|
<configuration>
|
|
<lifecycleMappingMetadata>
|
|
<pluginExecutions>
|
|
<pluginExecution>
|
|
<pluginExecutionFilter>
|
|
<groupId>org.springframework.cloud</groupId>
|
|
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
|
|
<versionRange>[1.0,)</versionRange>
|
|
<goals>
|
|
<goal>convert</goal>
|
|
</goals>
|
|
</pluginExecutionFilter>
|
|
<action>
|
|
<execute />
|
|
</action>
|
|
</pluginExecution>
|
|
</pluginExecutions>
|
|
</lifecycleMappingMetadata>
|
|
</configuration>
|
|
</plugin>
|
|
</plugins>
|
|
</pluginManagement>
|
|
</build></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_maven_plugin_with_spock_tests"><a class="link" href="#_maven_plugin_with_spock_tests">Maven Plugin with Spock Tests</a></h4>
|
|
<div class="paragraph">
|
|
<p>You can select the <a href="http://spockframework.org/">Spock Framework</a> for creating and executing the auto-generated contract
|
|
verification tests with both Maven and Gradle plugin. However, whereas with Gradle its really straightforward,
|
|
in Maven you will require some additional setup in order to make the tests compile and execute properly.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>First of all, you will have to use a plugin, such as <a href="https://github.com/groovy/GMavenPlus">GMavenPlus</a> plugin,
|
|
to add Groovy to your project. In GMavenPlus plugin, you will need to explicitly set test sources, including both the
|
|
path where your base test classes are defined and the path were the generated contract tests are added.
|
|
Please refer to the example below:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you uphold to the Spock convention of ending the test class names with <code>Spec</code>, you will also need to adjust your Maven
|
|
Surefire plugin setup, like in the following example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"></code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_stubs_and_transitive_dependencies"><a class="link" href="#_stubs_and_transitive_dependencies">Stubs and Transitive Dependencies</a></h3>
|
|
<div class="paragraph">
|
|
<p>The Maven and Gradle plugin that add the tasks that create the stubs jar for you. One
|
|
problem that arises is that, when reusing the stubs, you can mistakenly import all of
|
|
that stub’s dependencies. When building a Maven artifact, even though you have a couple
|
|
of different jars, all of them share one pom:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar
|
|
├── github-webhook-0.0.1.BUILD-20160903.075506-1-stubs.jar.sha1
|
|
├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar
|
|
├── github-webhook-0.0.1.BUILD-20160903.075655-2-stubs.jar.sha1
|
|
├── github-webhook-0.0.1.BUILD-SNAPSHOT.jar
|
|
├── github-webhook-0.0.1.BUILD-SNAPSHOT.pom
|
|
├── github-webhook-0.0.1.BUILD-SNAPSHOT-stubs.jar
|
|
├── ...
|
|
└── ...</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>There are three possibilities of working with those dependencies so as not to have any
|
|
issues with transitive dependencies:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>Mark all application dependencies as optional</p>
|
|
</li>
|
|
<li>
|
|
<p>Create a separate artifactid for the stubs</p>
|
|
</li>
|
|
<li>
|
|
<p>Exclude dependencies on the consumer side</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>Mark all application dependencies as optional</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If, in the <code>github-webhook</code> application, you mark all of your dependencies as optional,
|
|
when you include the <code>github-webhook</code> stubs in another application (or when that
|
|
dependency gets downloaded by Stub Runner) then, since all of the dependencies are
|
|
optional, they will not get downloaded.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>Create a separate <code>artifactid</code> for the stubs</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>If you create a separate <code>artifactid</code>, then you can set it up in whatever way you wish.
|
|
For example, you might decide to have no dependencies at all.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p><strong>Exclude dependencies on the consumer side</strong></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>As a consumer, if you add the stub dependency to your classpath, you can explicitly
|
|
exclude the unwanted dependencies.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="_scenarios"><a class="link" href="#_scenarios">Scenarios</a></h3>
|
|
<div class="paragraph">
|
|
<p>You can handle scenarios with Spring Cloud Contract Verifier. All you need to do is to
|
|
stick to the proper naming convention while creating your contracts. The convention
|
|
requires including an order number followed by an underscore. This will work regardles
|
|
of whether you’re working with YAML or Groovy. Example:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code>my_contracts_dir\
|
|
scenario1\
|
|
1_login.groovy
|
|
2_showCart.groovy
|
|
3_logout.groovy</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Such a tree causes Spring Cloud Contract Verifier to generate WireMock’s scenario with a
|
|
name of <code>scenario1</code> and the three following steps:</p>
|
|
</div>
|
|
<div class="olist arabic">
|
|
<ol class="arabic">
|
|
<li>
|
|
<p>login marked as <code>Started</code> pointing to…​</p>
|
|
</li>
|
|
<li>
|
|
<p>showCart marked as <code>Step1</code> pointing to…​</p>
|
|
</li>
|
|
<li>
|
|
<p>logout marked as <code>Step2</code> which will close the scenario.</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>More details about WireMock scenarios can be found at
|
|
<a href="https://wiremock.org/docs/stateful-behaviour/">https://wiremock.org/docs/stateful-behaviour/</a></p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect2">
|
|
<h3 id="docker-project"><a class="link" href="#docker-project">Docker Project</a></h3>
|
|
<div class="paragraph">
|
|
<p>We’re publishing a <code>springcloud/spring-cloud-contract</code> Docker image
|
|
that contains a project that will generate tests and execute them in <code>EXPLICIT</code> mode
|
|
against a running application.</p>
|
|
</div>
|
|
<div class="admonitionblock tip">
|
|
<table>
|
|
<tr>
|
|
<td class="icon">
|
|
<i class="fa icon-tip" title="Tip"></i>
|
|
</td>
|
|
<td class="content">
|
|
The <code>EXPLICIT</code> mode means that the tests generated from contracts will send
|
|
real requests and not the mocked ones.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_short_intro_to_maven_jars_and_binary_storage"><a class="link" href="#_short_intro_to_maven_jars_and_binary_storage">Short intro to Maven, JARs and Binary storage</a></h4>
|
|
<div class="paragraph">
|
|
<p>Since the Docker image can be used by non JVM projects, it’s good to
|
|
explain the basic terms behind Spring Cloud Contract packaging defaults.</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>Part of the following definitions were taken from the <a href="https://maven.apache.org/glossary.html">Maven Glossary</a></p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>Project</code>: Maven thinks in terms of projects. Everything that you
|
|
will build are projects. Those projects follow a well defined
|
|
“Project Object Model”. Projects can depend on other projects,
|
|
in which case the latter are called “dependencies”. A project may
|
|
consistent of several subprojects, however these subprojects are still
|
|
treated equally as projects.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>Artifact</code>: An artifact is something that is either produced or used
|
|
by a project. Examples of artifacts produced by Maven for a project
|
|
include: JARs, source and binary distributions. Each artifact
|
|
is uniquely identified by a group id and an artifact ID which is
|
|
unique within a group.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>JAR</code>: JAR stands for Java ARchive. It’s a format based on
|
|
the ZIP file format. Spring Cloud Contract packages the contracts and generated
|
|
stubs in a JAR file.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>GroupId</code>: A group ID is a universally unique identifier for a project.
|
|
While this is often just the project name (eg. commons-collections),
|
|
it is helpful to use a fully-qualified package name to distinguish it
|
|
from other projects with a similar name (eg. org.apache.maven).
|
|
Typically, when published to the Artifact Manager, the <code>GroupId</code> will get
|
|
slash separated and form part of the URL. E.g. for group id <code>com.example</code>
|
|
and artifact id <code>application</code> would be <code>/com/example/application/</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>Classifier</code>: The Maven dependency notation looks as follows:
|
|
<code>groupId:artifactId:version:classifier</code>. The classifier is additional suffix
|
|
passed to the dependency. E.g. <code>stubs</code>, <code>sources</code>. The same dependency
|
|
e.g. <code>com.example:application</code> can produce multiple artifacts that
|
|
differ from each other with the classifier.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>Artifact manager</code>: When you generate binaries / sources / packages, you would
|
|
like them to be available for others to download / reference or reuse. In case
|
|
of the JVM world those artifacts would be JARs, for Ruby these are gems
|
|
and for Docker those would be Docker images. You can store those artifacts
|
|
in a manager. Examples of such managers can be <a href="https://jfrog.com/artifactory/">Artifactory</a>
|
|
or <a href="https://www.sonatype.org/nexus/">Nexus</a>.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_how_it_works"><a class="link" href="#_how_it_works">How it works</a></h4>
|
|
<div class="paragraph">
|
|
<p>The image searches for contracts under the <code>/contracts</code> folder.
|
|
The output from running the tests will be available under
|
|
<code>/spring-cloud-contract/build</code> folder (it’s useful for debugging
|
|
purposes).</p>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>It’s enough for you to mount your contracts, pass the environment variables
|
|
and the image will:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>generate the contract tests</p>
|
|
</li>
|
|
<li>
|
|
<p>execute the tests against the provided URL</p>
|
|
</li>
|
|
<li>
|
|
<p>generate the <a href="https://github.com/tomakehurst/wiremock">WireMock</a> stubs</p>
|
|
</li>
|
|
<li>
|
|
<p>(optional - turned on by default) publish the stubs to a Artifact Manager</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="sect4">
|
|
<h5 id="_environment_variables"><a class="link" href="#_environment_variables">Environment Variables</a></h5>
|
|
<div class="paragraph">
|
|
<p>The Docker image requires some environment variables to point to
|
|
your running application, to the Artifact manager instance etc.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>PROJECT_GROUP</code> - your project’s group id. Defaults to <code>com.example</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>PROJECT_VERSION</code> - your project’s version. Defaults to <code>0.0.1-SNAPSHOT</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>PROJECT_NAME</code> - artifact id. Defaults to <code>example</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>PRODUCER_STUBS_CLASSIFIER</code> - archive classifier used for generated producer stubs, defaults to <code>stubs</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>REPO_WITH_BINARIES_URL</code> - URL of your Artifact Manager. Defaults to <code><a href="http://localhost:8081/artifactory/libs-release-local" class="bare">http://localhost:8081/artifactory/libs-release-local</a></code>
|
|
which is the default URL of <a href="https://jfrog.com/artifactory/">Artifactory</a> running locally</p>
|
|
</li>
|
|
<li>
|
|
<p><code>REPO_WITH_BINARIES_USERNAME</code> - (optional) username when the Artifact Manager is secured, defaults to <code>admin</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>REPO_WITH_BINARIES_PASSWORD</code> - (optional) password when the Artifact Manager is secured, defaults to <code>password</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>PUBLISH_ARTIFACTS</code> - if set to <code>true</code> then will publish artifact to binary storage. Defaults to <code>true</code>.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>These environment variables are used when contracts lay in an external repository. To enable
|
|
this feature you must set the <code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code> environment variable.</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_GROUP_ID</code> - group id of the project with contracts. Defaults to <code>com.example</code></p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code>- artifact id of the project with contracts.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_CLASSIFIER</code>- classifier of the project with contracts. Empty by default</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_VERSION</code> - version of the project with contracts. Defaults to <code>+</code>, equivalent to picking the latest</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code> - URL of your Artifact Manager. Defaults to value of <code>REPO_WITH_BINARIES_URL</code> env var.
|
|
If that’s not set, defaults to <code><a href="http://localhost:8081/artifactory/libs-release-local" class="bare">http://localhost:8081/artifactory/libs-release-local</a></code>
|
|
which is the default URL of <a href="https://jfrog.com/artifactory/">Artifactory</a> running locally</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME</code> - (optional) username if the <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>
|
|
requires authentication, defaults to <code>REPO_WITH_BINARIES_USERNAME</code>. If that’s not set defaults to <code>admin</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD</code> - (optional) password if the <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>
|
|
requires authentication, defaults to <code>REPO_WITH_BINARIES_PASSWORD</code>. If that’s not set defaults to <code>password</code>.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_PATH</code> - path to contracts for the given project, inside the project with contracts.
|
|
Defaults to slash separated <code>EXTERNAL_CONTRACTS_GROUP_ID</code> concatenated with <code>/</code> and <code>EXTERNAL_CONTRACTS_ARTIFACT_ID</code>. E.g.
|
|
for group id <code>foo.bar</code> and artifact id <code>baz</code>, would result in <code>foo/bar/baz</code> contracts path.</p>
|
|
</li>
|
|
<li>
|
|
<p><code>EXTERNAL_CONTRACTS_WORK_OFFLINE</code> - if set to <code>true</code> then will retrieve artifact with contracts
|
|
from the container’s <code>.m2</code>. Mount your local <code>.m2</code> as a volume available at the container’s <code>/root/.m2</code> path.
|
|
You must not set both <code>EXTERNAL_CONTRACTS_WORK_OFFLINE</code> and <code>EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL</code>.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>These environment variables are used when tests are executed:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p><code>APPLICATION_BASE_URL</code> - url against which tests should be executed.
|
|
Remember that it has to be accessible from the Docker container (e.g. <code>localhost</code>
|
|
will not work)</p>
|
|
</li>
|
|
<li>
|
|
<p><code>APPLICATION_USERNAME</code> - (optional) username for basic authentication to your application</p>
|
|
</li>
|
|
<li>
|
|
<p><code>APPLICATION_PASSWORD</code> - (optional) password for basic authentication to your application</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="_example_of_usage"><a class="link" href="#_example_of_usage">Example of usage</a></h4>
|
|
<div class="paragraph">
|
|
<p>Let’s take a look at a simple MVC application</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
|
|
$ cd bookstore</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>The contracts are available under <code>/contracts</code> folder.</p>
|
|
</div>
|
|
</div>
|
|
<div class="sect3">
|
|
<h4 id="docker-server-side"><a class="link" href="#docker-server-side">Server side (nodejs)</a></h4>
|
|
<div class="paragraph">
|
|
<p>Since we want to run tests, we could just execute:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ npm test</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>however, for learning purposes, let’s split it into pieces:</p>
|
|
</div>
|
|
<div class="listingblock">
|
|
<div class="content">
|
|
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash"># Stop docker infra (nodejs, artifactory)
|
|
$ ./stop_infra.sh
|
|
# Start docker infra (nodejs, artifactory)
|
|
$ ./setup_infra.sh
|
|
|
|
# Kill & Run app
|
|
$ pkill -f "node app"
|
|
$ nohup node app &
|
|
|
|
# Prepare environment variables
|
|
$ SC_CONTRACT_DOCKER_VERSION="..."
|
|
$ APP_IP="192.168.0.100"
|
|
$ APP_PORT="3000"
|
|
$ ARTIFACTORY_PORT="8081"
|
|
$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
|
|
$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
|
|
$ CURRENT_DIR="$( pwd )"
|
|
$ CURRENT_FOLDER_NAME=${PWD##*/}
|
|
$ PROJECT_VERSION="0.0.1.RELEASE"
|
|
|
|
# Execute contract tests
|
|
$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
|
|
|
|
# Kill app
|
|
$ pkill -f "node app"</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>What will happen is that via bash scripts:</p>
|
|
</div>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>infrastructure will be set up (MongoDb, Artifactory).
|
|
In real life scenario you would just run the NodeJS application
|
|
with mocked database. In this example we want to show how we can
|
|
benefit from Spring Cloud Contract in no time.</p>
|
|
</li>
|
|
<li>
|
|
<p>due to those constraints the contracts also represent the
|
|
stateful situation</p>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>first request is a <code>POST</code> that causes data to get inserted to the database</p>
|
|
</li>
|
|
<li>
|
|
<p>second request is a <code>GET</code> that returns a list of data with 1 previously inserted element</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<p>the NodeJS application will be started (on port <code>3000</code>)</p>
|
|
</li>
|
|
<li>
|
|
<p>contract tests will be generated via Docker and tests
|
|
will be executed against the running application</p>
|
|
<div class="ulist">
|
|
<ul>
|
|
<li>
|
|
<p>the contracts will be taken from <code>/contracts</code> folder.</p>
|
|
</li>
|
|
<li>
|
|
<p>the output of the test execution is available under
|
|
<code>node_modules/spring-cloud-contract/output</code>.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<p>the stubs will be uploaded to Artifactory. You can check them out
|
|
under <a href="http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/" class="bare">http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/</a> .
|
|
The stubs will be here <a href="http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar" class="bare">http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar</a>.</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="paragraph">
|
|
<p>To see how the client side looks like check out the <a href="#stubrunner-docker">[stubrunner-docker]</a> section.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript" src="js/tocbot/tocbot.min.js"></script>
|
|
<script type="text/javascript" src="js/toc.js"></script>
|
|
<link rel="stylesheet" href="js/highlight/styles/atom-one-dark-reasonable.min.css">
|
|
<script src="js/highlight/highlight.min.js"></script>
|
|
<script>hljs.initHighlighting()</script>
|
|
</body>
|
|
</html> |