3. Spring Cloud Contract Verifier Setup

3.1 Gradle Project

3.1.1 Prerequisites

In order to use Spring Cloud Contract Verifier with WireMock you have to use Gradle or Maven plugin.

[Warning]Warning

If you want to use Spock in your projects you have to add separately the spock-core and spock-spring modules. Check Spock docs for more information

3.1.2 Add gradle plugin with dependencies

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

3.1.3 Gradle and Rest Assured 3.0

By default Rest Assured 2.x is added to the classpath. However in order to give the users the opportunity to use Rest Assured 3.x it’s enough to add it to the plugins classpath.

buildscript {
	repositories {
		mavenCentral()
	}
	dependencies {
	    classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
		classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
		classpath "io.rest-assured:rest-assured:3.0.2"
		classpath "io.rest-assured:spring-mock-mvc:3.0.2"
	}
}

depenendencies {
    // all dependencies
    // you can exclude rest-assured from spring-cloud-contract-verifier
    testCompile "io.rest-assured:rest-assured:3.0.2"
    testCompile "io.rest-assured:spring-mock-mvc:3.0.2"
}

That way the plugin will automatically see that Rest Assured 3.x is present on the classpath and will modify the imports accordingly.

3.1.4 Snapshot versions for Gradle

Add the additional snapshot repository to your build.gradle to use snapshot versions which are automatically uploaded after every successful build:

buildscript {
	repositories {
		mavenCentral()
		mavenLocal()
		maven { url "http://repo.spring.io/snapshot" }
		maven { url "http://repo.spring.io/milestone" }
		maven { url "http://repo.spring.io/release" }
	}
}

3.1.5 Add stubs

By default Spring Cloud Contract Verifier is looking for stubs in src/test/resources/contracts directory.

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 which will be used as test class name. If there is more than one level of nested directories all except the last one will be used as package name. So with following structure

src/test/resources/contracts/myservice/shouldCreateUser.groovy
src/test/resources/contracts/myservice/shouldReturnUser.groovy

Spring Cloud Contract Verifier will create test class defaultBasePackage.MyService with two methods

  • shouldCreateUser()
  • shouldReturnUser()

3.1.6 Run plugin

Plugin registers itself to be invoked before check task. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke generateContractTests task.

3.1.7 Default setup

Default Gradle Plugin setup creates the following Gradle part of the build (it’s a pseudocode)

contracts {
    targetFramework = 'JUNIT'
    testMode = 'MockMvc'
    generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/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
        }
    }
}

3.1.8 Configure plugin

To change default configuration just add contracts snippet to your Gradle config

contracts {
	testMode = 'MockMvc'
	baseClassForTests = 'org.mycompany.tests'
	generatedTestSourcesDir = project.file('src/generatedContract')
}

3.1.9 Configuration options

  • testMode - defines mode for acceptance tests. By default MockMvc which is based on Spring’s MockMvc. It can also be changed to JaxRsClient or to Explicit for real HTTP calls.
  • imports - array with imports that should be included in generated tests (for example ['org.myorg.Matchers']). By default empty array []
  • staticImports - array with static imports that should be included in generated tests(for example ['org.myorg.Matchers.*']). By default empty array []
  • basePackageForTests - specifies base package for all generated tests. By default set to org.springframework.cloud.verifier.tests
  • baseClassForTests - base class for all generated tests. By default spock.lang.Specification if using Spock tests.
  • packageWithBaseClasses - instead of providing a fixed value for base class you can provide a package where all the base classes lay. Takes precedence over baseClassForTests.
  • baseClassMappings - explicitly map contract package to a FQN of a base class. Takes precedence over packageWithBaseClasses and baseClassForTests.
  • ruleClassForTests - specifies Rule which should be added to generated test classes.
  • ignoredFiles - Ant matcher allowing defining stub files for which processing should be skipped. By default empty array []
  • contractsDslDir - directory containing contracts written using the GroovyDSL. By default $rootDir/src/test/resources/contracts
  • generatedTestSourcesDir - test source directory where tests generated from Groovy DSL should be placed. By default $buildDir/generated-test-sources/contractVerifier
  • stubsOutputDir - dir where the generated WireMock stubs from Groovy DSL should be placed
  • targetFramework - the target test framework to be used; currently Spock and JUnit are supported with JUnit being the default framework

The following properties are used when you want to provide where the JAR with contract lays

  • contractDependency - the Dependency that provides groupid:artifactid:version:classifier coordinates. You can use the contractDependency closure to set it up
  • contractsPath - if contract deps are downloaded will default to groupid/artifactid where groupid will be slash separated. Otherwise will scan contracts under provided directory
  • contractsWorkOffline - in order not to download the dependencies each time you can download them once and work offline afterwards (reuse local Maven repo)

3.1.10 Single base class for all tests

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 endpoint which should be verified.

abstract class BaseMockMvcSpec extends Specification {

	def setup() {
		RestAssuredMockMvc.standaloneSetup(new PairIdController())
	}

	void isProperCorrelationId(Integer correlationId) {
		assert correlationId == 123456
	}

	void isEmpty(String value) {
		assert value == null
	}

}

In case of using Explicit mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of JAXRSCLIENT mode this base class should also contain protected WebTarget webTarget field, right now the only option to test JAX-RS API is to start a web server.

3.1.11 Different base classes for contracts

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:

  • follow a convention by providing the packageWithBaseClasses
  • provide explicit mapping via baseClassMappings

Convention

The convention is such that if you have a contract under e.g. src/test/resources/contract/foo/bar/baz/ and provide the value of the packageWithBaseClasses property to com.example.base then we will assume that there is a BarBazBase class under com.example.base package. In other words we take last two parts of package if they exist and form a class with a Base suffix. Takes precedence over baseClassForTests. Example of usage in the contracts closure:

packageWithBaseClasses = 'com.example.base'

Mapping

You can manually map a regular expression of the contract’s package to fully qualified name of the base class for the matched contract. Let’s take a look at the following example:

baseClassForTests = "com.example.FooBase"
baseClassMappings {
	baseClassMapping('.*/com/.*', 'com.example.ComBase')
	baseClassMapping('.*/bar/.*':'com.example.BarBase')
}

Let’s assume that you have contracts under - src/test/resources/contract/com/ - src/test/resources/contract/foo/

By providing the baseClassForTests we have a fallback in case mapping didn’t succeed (you could also provide the packageWithBaseClasses as fallback). That way the tests generated from src/test/resources/contract/com/ contracts will be extending the com.example.ComBase whereas the rest of tests will extend com.example.FooBase.

3.1.12 Invoking generated tests

To ensure that provider side is complaint with defined contracts, you need to invoke:

./gradlew generateContractTests test

3.1.13 Spring Cloud Contract Verifier on consumer side

In consumer service you need to configure Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. If you don’t want to use Stub Runner then you need to copy contracts stored in src/test/resources/contracts and generate WireMock json stubs using:

./gradlew generateClientStubs

Note that stubsOutputDir option has to be set for stub generation to work.

When present, json stubs can be used in consumer automated tests.

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

Underneath LoanApplication makes a call to FraudDetection service. This request is handled by WireMock server configured using stubs generated by Spring Cloud Contract Verifier.

3.2 Using in your Maven project

3.2.1 Add maven plugin

Add the Spring Cloud Contract BOM

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud-dependencies.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

Next, the Spring Cloud Contract Verifier Maven plugin

<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.fraud</packageWithBaseClasses>
	</configuration>
</plugin>

You can read more in the Spring Cloud Contract Maven Plugin Docs

3.2.2 Maven and Rest Assured 3.0

By default Rest Assured 2.x is added to the classpath. However in order to give the users the opportunity to use Rest Assured 3.x it’s enough to add it to the plugins classpath.

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <packageWithBaseClasses>com.example</packageWithBaseClasses>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-verifier</artifactId>
            <version>${spring-cloud-contract.version}</version>
        </dependency>
        <dependency>
           <groupId>io.rest-assured</groupId>
           <artifactId>rest-assured</artifactId>
           <version>3.0.2</version>
           <scope>compile</scope>
        </dependency>
        <dependency>
           <groupId>io.rest-assured</groupId>
           <artifactId>spring-mock-mvc</artifactId>
           <version>3.0.2</version>
           <scope>compile</scope>
        </dependency>
    </dependencies>
</plugin>

<dependencies>
    <!-- all dependencies -->
    <!-- you can exclude rest-assured from spring-cloud-contract-verifier -->
    <dependency>
       <groupId>io.rest-assured</groupId>
       <artifactId>rest-assured</artifactId>
       <version>3.0.2</version>
       <scope>test</scope>
    </dependency>
    <dependency>
       <groupId>io.rest-assured</groupId>
       <artifactId>spring-mock-mvc</artifactId>
       <version>3.0.2</version>
       <scope>test</scope>
    </dependency>
</dependencies>

That way the plugin will automatically see that Rest Assured 3.x is present on the classpath and will modify the imports accordingly.

3.2.3 Snapshot versions for Maven

For Snapshot / Milestone versions you have to add the following section to your pom.xml

<repositories>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
	<repository>
		<id>spring-releases</id>
		<name>Spring Releases</name>
		<url>https://repo.spring.io/release</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>
<pluginRepositories>
	<pluginRepository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</pluginRepository>
	<pluginRepository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
	<pluginRepository>
		<id>spring-releases</id>
		<name>Spring Releases</name>
		<url>https://repo.spring.io/release</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
</pluginRepositories>

3.2.4 Add stubs

By default Spring Cloud Contract Verifier is looking for stubs in src/test/resources/contracts directory. 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 which will be used as test class name. If there is more than one level of nested directories all except the last one will be used as package name. So with following structure

src/test/resources/contracts/myservice/shouldCreateUser.groovy
src/test/resources/contracts/myservice/shouldReturnUser.groovy

Spring Cloud Contract Verifier will create test class defaultBasePackage.MyService with two methods - shouldCreateUser() - shouldReturnUser()

3.2.5 Run plugin

Plugin goal generateTests is assigned to be invoked in phase generate-test-sources. You have nothing to do as long as you want it to be part of your build process. If you just want to generate tests please invoke generateTests goal.

3.2.6 Configure plugin

To change default configuration just add configuration section to plugin definition or execution definition.

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

3.2.7 Important configuration options

  • testMode - defines mode for acceptance tests. By default MockMvc which is based on Spring’s MockMvc. It can also be changed to JaxRsClient or to Explicit for real HTTP calls.
  • basePackageForTests - specifies base package for all generated tests. By default set to org.springframework.cloud.verifier.tests.
  • ruleClassForTests - specifies Rule which should be added to generated test classes.
  • baseClassForTests - base class for generated tests. By default spock.lang.Specification if using Spock tests.
  • contractsDirectory - directory containing contracts written using the GroovyDSL. By default /src/test/resources/contracts.
  • testFramework - the target test framework to be used; currently Spock and JUnit are supported with JUnit being the default framework
  • packageWithBaseClasses - instead of providing a fixed value for base class you can provide a package where all the base classes lay. The convention is such that if you have a contract under src/test/resources/contract/foo/bar/baz/ and provide the value of this property to com.example.base then we will assume that there is a BarBazBase class under com.example.base package. Takes precedence over baseClassForTests
  • baseClassMappings - list of base class mappings that where you have to provide contractPackageRegex which is checked against the package in which the contract lays and baseClassFQN that maps to fully qualified name of the base class for the matched contract. If you have a contract under src/test/resources/contract/foo/bar/baz/ and map the property .*com.example.base.BaseClass then the test class generated from these contracts will extend com.example.base.BaseClass. Takes precedence over packageWithBaseClasses and baseClassForTests.

If you want to download your contract definitions from a Maven repository you can use

  • contractDependency - the contract dependency that contains all the packaged contracts
  • contractsPath - path to concrete contracts in the JAR with packaged contracts. Defaults to groupid/artifactid where gropuid is slash separated.
  • contractsWorkOffline - if the dependencies should be downloaded or local Maven only should be reused
  • contractsRepositoryUrl - DEPRECATED PROPERTY - please use the contractRepository closure - URL to a repo with the artifacts with contracts, if not provided should use the current Maven ones
  • contractRepository - closure where you can define properties related to repository with contracts

    • username - username to be used to connect to the repo
    • password - username to be used to connect to the repo
    • proxyHost - proxy host to be used to connect to the repo
    • proxyPort - proxy port to be used to connect to the repo
    • cacheDownloadedContracts - if you want to reuse download JARs that contain contract definitions. We cache only non-snapshot, explicitly provided versions (e.g. + or 1.0.0.BUILD-SNAPSHOT won’t get cached). By default this feature is turned on.

3.2.8 Single base class for all tests

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 endpoint which should be verified.

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

In case of using Explicit mode, you can use base class to initialize the whole tested app similarly as in regular integration tests. In case of JAXRSCLIENT mode this base class should also contain protected WebTarget webTarget field, right now the only option to test JAX-RS API is to start a web server.

3.2.9 Different base classes for contracts

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:

  • follow a convention by providing the packageWithBaseClasses
  • provide explicit mapping via baseClassMappings

Convention

The convention is such that if you have a contract under e.g. src/test/resources/contract/hello/v1/ and provide the value of the packageWithBaseClasses property to hello then we will assume that there is a HelloV1Base class under hello package. In other words we take last two parts of package if they exist and form a class with a Base suffix. Takes precedence over baseClassForTests. Example of usage:

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<packageWithBaseClasses>hello</packageWithBaseClasses>
	</configuration>
</plugin>

Mapping

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 baseClassMappings of baseClassMapping that takes a contractPackageRegex to baseClassFQN mapping. Let’s take a look at the following example:

<plugin>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-contract-maven-plugin</artifactId>
	<configuration>
		<baseClassForTests>com.example.FooBase</baseClassForTests>
		<baseClassMappings>
			<baseClassMapping>
				<contractPackageRegex>.*com.*</contractPackageRegex>
				<baseClassFQN>com.example.TestBase</baseClassFQN>
			</baseClassMapping>
		</baseClassMappings>
	</configuration>
</plugin>

Let’s assume that you have contracts under - src/test/resources/contract/com/ - src/test/resources/contract/foo/

By providing the baseClassForTests we have a fallback in case mapping didn’t succeed (you could also provide the packageWithBaseClasses as fallback). That way the tests generated from src/test/resources/contract/com/ contracts will be extending the com.example.ComBase whereas the rest of tests will extend com.example.FooBase.

3.2.10 Invoking generated tests

Spring Cloud Contract Maven Plugin generates verification code into directory /generated-test-sources/contractVerifier and attach this directory to testCompile goal.

For Groovy Spock code use:

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

To ensure that provider side is complaint with defined contracts, you need to invoke mvn generateTest test

3.2.11 FAQ with Maven Plugin

3.2.12 Maven Plugin and STS

In case you see the following exception while using STS

STS Exception

when you click on the marker you should see sth like this

 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

In order to fix this issue just provide the following section in your pom.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>

3.2.13 Spring Cloud Contract Verifier on consumer side

You can actually use the Spring Cloud Contract Verifier also for the consumer side! You can use the plugin so that it only converts the contracts and generates the stubs. To achieve that you need to configure Spring Cloud Contract Verifier plugin in exactly the same way as in case of provider. You need to copy contracts stored in src/test/resources/contracts and generate WireMock json stubs using: mvn generateStubs command. By default generated WireMock mapping is stored in directory target/mappings. Your project should create from this generated mappings additional artifact with classifier stubs for easy deploy to maven repository.

Sample configuration:

<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${verifier-plugin.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>convert</goal>
                <goal>generateStubs</goal>
            </goals>
        </execution>
    </executions>
</plugin>

When present, json stubs can be used in consumer automated tests.

@RunWith(SpringTestRunner.class)
@SpringBootTest
@AutoConfigureStubRunner
public class LoanApplicationServiceTests {

  @Autowired
  LoanApplicationService service;

  @Test
  public void shouldSuccessfullyApplyForLoan() {
    //given:
 	LoanApplication application =
			new LoanApplication(new Client("12345678901"), 123.123);
    //when:
	LoanApplicationResult loanApplication = service.loanApplication(application);
    // then:
	assertThat(loanApplication.loanApplicationStatus).isEqualTo(LoanApplicationStatus.LOAN_APPLIED);
	assertThat(loanApplication.rejectionReason).isNull();
  }
}

Underneath LoanApplication makes a call to the FraudDetection service. This request is handled by a WireMock server configured using stubs generated by Spring Cloud Contract Verifier.

3.3 Scenarios

It’s possible to handle scenarios with Spring Cloud Contract Verifier. All you need to do is to stick to proper naming convention while creating your contracts. The convention requires to include order number followed by the underscore.

my_contracts_dir\
  scenario1\
    1_login.groovy
    2_showCart.groovy
    3_logout.groovy

Such tree will cause Spring Cloud Contract Verifier generating WireMock’s scenario with name scenario1 and three steps:

  • login marked as Started pointing to:
  • showCart marked as Step1 pointing to:
  • logout marked as Step2 which will close the scenario.

More details about WireMock scenarios can be found under http://wiremock.org/stateful-behaviour.html

Spring Cloud Contract Verifier will also generate tests with guaranteed order of execution.

3.4 Stubs and transitive dependencies

The Maven and Gradle plugin that we’re created are adding the tasks that create the stubs jar for you. What can be problematic is that when reusing the stubs you can by mistake import all of that stub dependencies! When building a Maven artifact even though you have a couple of different jars, all of them share one pom:

├── 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
├── ...
└── ...

There are three possibilities of working with those dependencies so as not to have any issues with transitive dependencies.

Mark all application dependencies as optional

If in the github-webhook application we would mark all of our dependencies as optional, when you include the github-webhook stubs in another application (or when that dependency gets downloaded by Stub Runner) then, since all of the depenencies are optional, they will not get downloaded.

Create a separate artifactid for stubs

If you create a separate artifactid then you can set it up in whatever way you wish. For example by having no dependencies at all.

Exclude dependencies on the consumer side

As a consumer, if you add the stub dependency to your classpath you can explicitly exclude the unwanted dependencies.