Spring Cloud Contract Verifier lets you verify applications that use messaging as a means of communication. All of the integrations shown in this document work with Spring, but you can also create one of your own and use that.
You can use one of the following four integration configurations:
Since we use Spring Boot, if you have added one of these libraries to the classpath, all the messaging configuration is automatically set up.
![]() | Important |
|---|---|
Remember to put |
![]() | Important |
|---|---|
If you want to use Spring Cloud Stream, remember to add a dependency on
|
Maven.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-test-support</artifactId> <scope>test</scope> </dependency>
Gradle.
testCompile "org.springframework.cloud:spring-cloud-stream-test-support"
The main interface used by the tests is
org.springframework.cloud.contract.verifier.messaging.MessageVerifier.
It defines how to send and receive messages. You can create your own implementation to
achieve the same goal.
In a test, you can inject a ContractVerifierMessageExchange to send and receive
messages that follow the contract. Then add @AutoConfigureMessageVerifier to your test.
Here’s an example:
@RunWith(SpringTestRunner.class) @SpringBootTest @AutoConfigureMessageVerifier public static class MessagingContractTests { @Autowired private MessageVerifier verifier; ... }
![]() | Note |
|---|---|
If your tests require stubs as well, then |
Having the input or outputMessage sections in your DSL results in creation of tests
on the publisher’s side. By default, JUnit tests are created. However, there is also a
possibility to create Spock tests.
There are 3 main scenarios that we should take into consideration:
![]() | Important |
|---|---|
The destination passed to |
For the given contract:
Groovy DSL.
def contractDsl = Contract.make {
label 'some_label'
input {
triggeredBy('bookReturnedTriggered()')
}
outputMessage {
sentTo('activemq:output')
body('''{ "bookName" : "foo" }''')
headers {
header('BOOK-NAME', 'foo')
messagingContentType(applicationJson())
}
}
}
YAML.
label: some_label
input:
triggeredBy: bookReturnedTriggered
outputMessage:
sentTo: activemq:output
body:
bookName: foo
headers:
BOOK-NAME: foo
contentType: application/json
The following JUnit test is created:
''' // when: bookReturnedTriggered(); // then: ContractVerifierMessage response = contractVerifierMessaging.receive("activemq:output"); assertThat(response).isNotNull(); assertThat(response.getHeader("BOOK-NAME")).isNotNull(); assertThat(response.getHeader("BOOK-NAME").toString()).isEqualTo("foo"); assertThat(response.getHeader("contentType")).isNotNull(); assertThat(response.getHeader("contentType").toString()).isEqualTo("application/json"); // and: DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); assertThatJson(parsedJson).field("bookName").isEqualTo("foo"); '''
And the following Spock test would be created:
''' when: bookReturnedTriggered() then: ContractVerifierMessage response = contractVerifierMessaging.receive('activemq:output') assert response != null response.getHeader('BOOK-NAME')?.toString() == 'foo' response.getHeader('contentType')?.toString() == 'application/json' and: DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) assertThatJson(parsedJson).field("bookName").isEqualTo("foo") '''
For the given contract:
Groovy DSL.
def contractDsl = Contract.make {
label 'some_label'
input {
messageFrom('jms:input')
messageBody([
bookName: 'foo'
])
messageHeaders {
header('sample', 'header')
}
}
outputMessage {
sentTo('jms:output')
body([
bookName: 'foo'
])
headers {
header('BOOK-NAME', 'foo')
}
}
}
YAML.
label: some_label
input:
messageFrom: jms:input
messageBody:
bookName: 'foo'
messageHeaders:
sample: header
outputMessage:
sentTo: jms:output
body:
bookName: foo
headers:
BOOK-NAME: foo
The following JUnit test is created:
''' // given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( "{\\"bookName\\":\\"foo\\"}" , headers() .header("sample", "header")); // when: contractVerifierMessaging.send(inputMessage, "jms:input"); // then: ContractVerifierMessage response = contractVerifierMessaging.receive("jms:output"); assertThat(response).isNotNull(); assertThat(response.getHeader("BOOK-NAME")).isNotNull(); assertThat(response.getHeader("BOOK-NAME").toString()).isEqualTo("foo"); // and: DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.getPayload())); assertThatJson(parsedJson).field("bookName").isEqualTo("foo"); '''
And the following Spock test would be created:
"""\ given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( '''{"bookName":"foo"}''', ['sample': 'header'] ) when: contractVerifierMessaging.send(inputMessage, 'jms:input') then: ContractVerifierMessage response = contractVerifierMessaging.receive('jms:output') assert response !- null response.getHeader('BOOK-NAME')?.toString() == 'foo' and: DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) assertThatJson(parsedJson).field("bookName").isEqualTo("foo") """
For the given contract:
Groovy DSL.
def contractDsl = Contract.make {
label 'some_label'
input {
messageFrom('jms:delete')
messageBody([
bookName: 'foo'
])
messageHeaders {
header('sample', 'header')
}
assertThat('bookWasDeleted()')
}
}
YAML.
label: some_label
input:
messageFrom: jms:delete
messageBody:
bookName: 'foo'
messageHeaders:
sample: header
assertThat: bookWasDeleted()
The following JUnit test is created:
''' // given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( "{\\"bookName\\":\\"foo\\"}" , headers() .header("sample", "header")); // when: contractVerifierMessaging.send(inputMessage, "jms:delete"); // then: bookWasDeleted(); '''
And the following Spock test would be created:
''' given: ContractVerifierMessage inputMessage = contractVerifierMessaging.create( \'\'\'{"bookName":"foo"}\'\'\', ['sample': 'header'] ) when: contractVerifierMessaging.send(inputMessage, 'jms:delete') then: noExceptionThrown() bookWasDeleted() '''
Unlike the HTTP part, in messaging, we need to publish the Groovy DSL inside the JAR with a stub. Then it is parsed on the consumer side and proper stubbed routes are created.
For more information, see Chapter 7, Stub Runner for Messaging section.
Maven.
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-test-support</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.BUILD-SNAPSHOT</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Gradle.
ext {
contractsDir = file("mappings")
stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/")
}
// Automatically added by plugin:
// copyContracts - copies contracts to the output folder from which JAR will be created
// verifierStubsJar - JAR with a provided stub suffix
// the presented publication is also added by the plugin but you can modify it as you wish
publishing {
publications {
stubs(MavenPublication) {
artifactId "${project.name}-stubs"
artifact verifierStubsJar
}
}
}