|
|
|
|
@@ -1,33 +1,36 @@
|
|
|
|
|
== Contract DSL
|
|
|
|
|
|
|
|
|
|
IMPORTANT: Remember that, inside the contract file, you have to provide the fully
|
|
|
|
|
Spring Cloud Contract supports out of the box 2 types of DSL. One written in
|
|
|
|
|
`Groovy` and one written in `YAML`.
|
|
|
|
|
|
|
|
|
|
If you decide to write the contract in Groovy, do not be alarmed if you have not used Groovy
|
|
|
|
|
before. Knowledge of the language is not really needed, as the Contract DSL uses only a
|
|
|
|
|
tiny subset of it (only literals, method calls and closures). Also, the DSL is statically
|
|
|
|
|
typed, to make it programmer-readable without any knowledge of the DSL itself.
|
|
|
|
|
|
|
|
|
|
IMPORTANT: Remember that, inside the Groovy contract file, you have to provide the fully
|
|
|
|
|
qualified name to the `Contract` class and `make` static imports, such as
|
|
|
|
|
`org.springframework.cloud.spec.Contract.make { ... }`. You can also provide an import to
|
|
|
|
|
the `Contract` class: `import org.springframework.cloud.spec.Contract` and then call
|
|
|
|
|
`Contract.make { ... }`.
|
|
|
|
|
|
|
|
|
|
Contract DSL is written in Groovy, but do not be alarmed if you have not used Groovy
|
|
|
|
|
before. Knowledge of the language is not really needed, as the Contract DSL uses only a
|
|
|
|
|
tiny subset of it (only literals, method calls and closures). Also, the DSL is statically
|
|
|
|
|
typed, to make it programmer-readable without any knowledge of the DSL itself.
|
|
|
|
|
|
|
|
|
|
TIP: Spring Cloud Contract supports defining multiple contracts in a single file.
|
|
|
|
|
|
|
|
|
|
The Contract is present in the `spring-cloud-contract-spec` module of the
|
|
|
|
|
https://github.com/spring-cloud/spring-cloud-contract/tree/master/spring-cloud-contract-verifier[Spring
|
|
|
|
|
Cloud Contract Verifier repository].
|
|
|
|
|
|
|
|
|
|
The following is a complete example of a contract definition:
|
|
|
|
|
The following is a complete example of a Groovy contract definition:
|
|
|
|
|
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=dsl_example,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
NOTE: The preceding example does not contain all the features of the DSL appear. The
|
|
|
|
|
remainder of this section describes the other features.
|
|
|
|
|
The following is a complete example of a YAML contract definition:
|
|
|
|
|
|
|
|
|
|
You can compile Contracts to WireMock stubs mapping using standalone maven command:
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
TIP: You can compile contracts to stubs mapping using standalone maven command:
|
|
|
|
|
`mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert`
|
|
|
|
|
|
|
|
|
|
=== Limitations
|
|
|
|
|
@@ -41,7 +44,7 @@ to turn it on, please set the value of the following system property to `true`:
|
|
|
|
|
You can also provide the `assertJsonSize` property in the plugin configuration.
|
|
|
|
|
|
|
|
|
|
WARNING: Because JSON structure can have any form, it can be impossible to parse it
|
|
|
|
|
properly when using the `value(consumer(...), producer(...))` notation in `GString`. That
|
|
|
|
|
properly when using the Groovy DSL and the `value(consumer(...), producer(...))` notation in `GString`. That
|
|
|
|
|
is why you should use the Groovy Map notation.
|
|
|
|
|
|
|
|
|
|
=== Common Top-Level elements
|
|
|
|
|
@@ -60,11 +63,18 @@ The following sections describe the most common top-level elements:
|
|
|
|
|
You can add a `description` to your contract. The description is arbitrary text. The
|
|
|
|
|
following code shows an example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=description,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[[contract-dsl-name]]
|
|
|
|
|
==== Name
|
|
|
|
|
|
|
|
|
|
@@ -78,17 +88,36 @@ generated test not compile. Also, remember that, if you provide the same name fo
|
|
|
|
|
multiple contracts, your autogenerated tests fail to compile and your generated stubs
|
|
|
|
|
override each other.
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=name,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=name,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[[contract-dsl-ignoring-contracts]]
|
|
|
|
|
==== Ignoring Contracts
|
|
|
|
|
|
|
|
|
|
If you want to ignore a contract, you can either set a value of ignored contracts in the
|
|
|
|
|
plugin configuration or set the `ignored` property on the contract itself:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{contract_spec_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=ignored,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[[contract-dsl-passing-values-from-files]]
|
|
|
|
|
==== Passing Values from Files
|
|
|
|
|
|
|
|
|
|
@@ -108,11 +137,18 @@ following resources in our project.
|
|
|
|
|
|
|
|
|
|
Further assume that your contract is as follows:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/classpath/readFromFile.groovy[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_from_file.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Further assume that the JSON files is as follows:
|
|
|
|
|
|
|
|
|
|
*request.json*
|
|
|
|
|
@@ -128,9 +164,8 @@ include::{verifier_core_path}/src/test/resources/classpath/response.json[indent=
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
When test or stub generation takes place, the contents of the file is passed to the body
|
|
|
|
|
of a request or a response. That works because of the `file(...)` method. The argument of
|
|
|
|
|
that method needs to be a file with location relative to the folder in which the contract
|
|
|
|
|
lays.
|
|
|
|
|
of a request or a response. The name of the file needs to be a file with location
|
|
|
|
|
relative to the folder in which the contract lays.
|
|
|
|
|
|
|
|
|
|
[[contract-dsl-http-top-level-elements]]
|
|
|
|
|
==== HTTP Top-Level Elements
|
|
|
|
|
@@ -138,62 +173,124 @@ lays.
|
|
|
|
|
The following methods can be called in the top-level closure of a contract definition.
|
|
|
|
|
`request` and `response` are mandatory. `priority` is optional.
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=priority,indent=0]
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
|
|
|
|
...
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
|
|
|
|
|
...
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
IMPORTANT: If you want to make your contract have a **higher** value of priority
|
|
|
|
|
you need to pass a **lower** number to the `priority` tag / method. E.g. `priority` with
|
|
|
|
|
value `5` has **higher** priority than `priority` with value `10`.
|
|
|
|
|
|
|
|
|
|
=== Request
|
|
|
|
|
|
|
|
|
|
The HTTP protocol requires only **method and address** to be specified in a request. The
|
|
|
|
|
The HTTP protocol requires only **method and url** to be specified in a request. The
|
|
|
|
|
same information is mandatory in request definition of the Contract.
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=request,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request_obligatory,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
It is possible to specify an absolute rather than relative `url`, but using `urlPath` is
|
|
|
|
|
the recommended way, as doing so makes the tests **host-independent**.
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=url,indent=0]
|
|
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain **query parameters**, which are specified in a closure nested in a
|
|
|
|
|
call to `urlPath` or `url`.
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_rest_with_path.yml[tags=url_path,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain **query parameters**.
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=urlpath,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
|
|
|
|
...
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=query_params,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain additional **request headers**, as shown in the following example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=headers,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain a **request body**, as shown in the following example:
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
|
|
|
|
...
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=headers,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain a **request body**:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain **multipart** elements. To include multipart elements, call the
|
|
|
|
|
`multipart()` method, as shown in the following example
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
|
|
|
|
|
...
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=body,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
`request` may contain **multipart** elements. To include multipart elements, use the
|
|
|
|
|
`multipart` method/section, as shown in the following examples
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=multipartdsl,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_multipart.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
In the preceding example, we define parameters in either of two ways:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
* Directly, by using the map notation, where the value can be a dynamic property (such as
|
|
|
|
|
`formParameter: $(consumer(...), producer(...))`).
|
|
|
|
|
* By using the `named(...)` method that lets you set a named parameter. A named parameter
|
|
|
|
|
@@ -201,6 +298,20 @@ can set a `name` and `content`. You can call it either via a method with two ar
|
|
|
|
|
such as `named("fileName", "fileContent")`, or via a map notation, such as
|
|
|
|
|
`named(name: "fileName", content: "fileContent")`.
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
* The multipart parameters are set via `multipart.params` section
|
|
|
|
|
* The named parameters (the `fileName` and `fileContent` for a given parameter name)
|
|
|
|
|
can be set via the `multipart.named` section. That section contains
|
|
|
|
|
the `paramName` (name of the parameter), `fileName` (name of the file),
|
|
|
|
|
`fileContent` (content of the file) fields
|
|
|
|
|
* The dynamic bits can be set via the `matchers.multipart` section
|
|
|
|
|
** for parameters use the `params` section that can accept
|
|
|
|
|
`regex` or a `predefined` regular expression
|
|
|
|
|
** for named params use the `named` section where first you
|
|
|
|
|
define the parameter name via `paramName` and then you can pass the
|
|
|
|
|
parametrization of either `fileName` or `fileContent` via
|
|
|
|
|
`regex` or a `predefined` regular expression
|
|
|
|
|
|
|
|
|
|
From this contract, the generated test is as follows:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
@@ -227,17 +338,26 @@ The WireMock stub is as follows:
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
=== Response
|
|
|
|
|
|
|
|
|
|
The response must contain an **HTTP status code** and may contain other information. The
|
|
|
|
|
following code shows an example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=response,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
|
|
|
|
|
...
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response_obligatory,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Besides status, the response may contain **headers** and a **body**, both of which are
|
|
|
|
|
specified the same way as in the request (see the previous paragraph).
|
|
|
|
|
|
|
|
|
|
@@ -245,12 +365,19 @@ specified the same way as in the request (see the previous paragraph).
|
|
|
|
|
|
|
|
|
|
The contract can contain some dynamic properties: timestamps, IDs, and so on. You do not
|
|
|
|
|
want to force the consumers to stub their clocks to always return the same value of time
|
|
|
|
|
so that it gets matched by the stub. You can provide the dynamic parts in your contracts
|
|
|
|
|
so that it gets matched by the stub.
|
|
|
|
|
|
|
|
|
|
For Groovy DSL you can provide the dynamic parts in your contracts
|
|
|
|
|
in two ways: pass them directly in the body or set them in separate sections called
|
|
|
|
|
`testMatchers` and `stubMatchers`.
|
|
|
|
|
|
|
|
|
|
For YAML you can only use the `matchers` section.
|
|
|
|
|
|
|
|
|
|
==== Dynamic properties inside the body
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
|
|
|
|
<<contract-matchers>> section for YAML examples of a similar feature.
|
|
|
|
|
|
|
|
|
|
You can set the properties inside the body either with the `value` method or, if you use
|
|
|
|
|
the Groovy map notation, with `$()`. The following example shows how to set dynamic
|
|
|
|
|
properties with the value method:
|
|
|
|
|
@@ -278,6 +405,9 @@ method. Subsequent sections take a closer look at what you can do with those val
|
|
|
|
|
|
|
|
|
|
==== Regular expressions
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
|
|
|
|
<<contract-matchers>> section for YAML examples of a similar feature.
|
|
|
|
|
|
|
|
|
|
You can use regular expressions to write your requests in Contract DSL. Doing so is
|
|
|
|
|
particularly useful when you want to indicate that a given response should be provided
|
|
|
|
|
for requests that follow a given pattern. Also, you can use regular expressions when you
|
|
|
|
|
@@ -319,6 +449,9 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
|
|
|
|
|
|
|
|
|
==== Passing Optional Parameters
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
|
|
|
|
<<contract-matchers>> section for YAML examples of a similar feature.
|
|
|
|
|
|
|
|
|
|
It is possible to provide optional parameters in your contract. However, you can provide
|
|
|
|
|
optional parameters only for the following:
|
|
|
|
|
|
|
|
|
|
@@ -351,6 +484,9 @@ include::{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/spr
|
|
|
|
|
|
|
|
|
|
==== Executing Custom Methods on the Server Side
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL. Check out the
|
|
|
|
|
<<contract-matchers>> section for YAML examples of a similar feature.
|
|
|
|
|
|
|
|
|
|
You can define a method call that executes on the server side during the test. Such a
|
|
|
|
|
method can be added to the class defined as "baseClassForTests" in the configuration. The
|
|
|
|
|
following code shows an example of the contract portion of the test case:
|
|
|
|
|
@@ -414,7 +550,9 @@ It should resemble the following code:
|
|
|
|
|
==== Referencing the Request from the Response
|
|
|
|
|
|
|
|
|
|
The best situation is to provide fixed values, but sometimes you need to reference a
|
|
|
|
|
request in your response. To do so, you can use the `fromRequest()` method, which lets
|
|
|
|
|
request in your response.
|
|
|
|
|
|
|
|
|
|
If you're writing contracts using Groovy DSL, you can use the `fromRequest()` method, which lets
|
|
|
|
|
you reference a bunch of elements from the HTTP request. You can use the following
|
|
|
|
|
options:
|
|
|
|
|
|
|
|
|
|
@@ -430,13 +568,36 @@ given name.
|
|
|
|
|
* `fromRequest().body(String jsonPath)`: Returns the element from the request that
|
|
|
|
|
matches the JSON Path.
|
|
|
|
|
|
|
|
|
|
If you're using the YAML contract definition you have to use the
|
|
|
|
|
http://handlebarsjs.com/[Handlebars] `{{{ }}}` notation with custom, Spring Cloud Contract
|
|
|
|
|
functions to achieve this.
|
|
|
|
|
|
|
|
|
|
* `{{{ request.url }}}`: Returns the request URL and query parameters.
|
|
|
|
|
* `{{{ request.query.key.[index] }}}`: Returns the nth query parameter with a given name.
|
|
|
|
|
E.g. for key `foo`, first entry `{{{ request.query.foo.[0] }}}`
|
|
|
|
|
* `{{{ request.path }}}`: Returns the full path.
|
|
|
|
|
* `{{{ request.path.[index] }}}`: Returns the nth path element. E.g.
|
|
|
|
|
for first entry ```{{{ request.path.[0] }}}
|
|
|
|
|
* `{{{ request.headers.key }}}`: Returns the first header with a given name.
|
|
|
|
|
* `{{{ request.headers.key.[index] }}}`: Returns the nth header with a given name.
|
|
|
|
|
* `{{{ request.body }}}`: Returns the full request body.
|
|
|
|
|
* `{{{ jsonpath this 'your.json.path' }}}`: Returns the element from the request that
|
|
|
|
|
matches the JSON Path. E.g. for json path `$.foo` - `{{{ jsonpath this '$.foo' }}}`
|
|
|
|
|
|
|
|
|
|
Consider the following contract:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=template_contract,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_reference_request.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Running a JUnit test generation leads to a test that resembles the following example:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
@@ -561,6 +722,7 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
|
|
|
|
IMPORTANT: Remember to override the `applyGlobally()` method and set it to `false` if you
|
|
|
|
|
want the transformation to be applied only for a mapping that explicitly requires it.
|
|
|
|
|
|
|
|
|
|
[[contract-matchers]]
|
|
|
|
|
==== Dynamic Properties in the Matchers Sections
|
|
|
|
|
|
|
|
|
|
If you work with https://docs.pact.io/[Pact], the following discussion may seem familiar.
|
|
|
|
|
@@ -577,6 +739,8 @@ contract.
|
|
|
|
|
Currently, Spring Cloud Contract Verifier supports only JSON Path-based matchers with the
|
|
|
|
|
following matching possibilities:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
|
|
|
|
|
* For `stubMatchers`:
|
|
|
|
|
** `byEquality()`: The value taken from the response via the provided JSON Path must be
|
|
|
|
|
equal to the value provided in the contract.
|
|
|
|
|
@@ -615,13 +779,63 @@ following, depending on the JSON path:
|
|
|
|
|
*** `Number`: If you point to `Integer`, `Double`, or other kind of number.
|
|
|
|
|
*** `Boolean`: If you point to a `Boolean`.
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
|
|
|
|
|
_Please read the Groovy section for detailed explanation of
|
|
|
|
|
what the types mean_
|
|
|
|
|
|
|
|
|
|
For YAML the structure of a matcher looks like this
|
|
|
|
|
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
- path: $.foo
|
|
|
|
|
type: by_regex
|
|
|
|
|
value: bar
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Or if you want to use one of the predefined regular expressions
|
|
|
|
|
`[only_alpha_unicode, number, any_boolean, ip_address, hostname,
|
|
|
|
|
email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_empty, non_blank]`:
|
|
|
|
|
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
- path: $.foo
|
|
|
|
|
type: by_regex
|
|
|
|
|
predefined: only_alpha_unicode
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Below you can find the allowed list of `type`s.
|
|
|
|
|
|
|
|
|
|
* For `stubMatchers`:
|
|
|
|
|
** `by_equality`
|
|
|
|
|
** `by_regex`
|
|
|
|
|
** `by_date`
|
|
|
|
|
** `by_timestamp`
|
|
|
|
|
** `by_time`
|
|
|
|
|
* For `testMatchers`:
|
|
|
|
|
** `by_equality`
|
|
|
|
|
** `by_regex`
|
|
|
|
|
** `by_date`
|
|
|
|
|
** `by_timestamp`
|
|
|
|
|
** `by_time`
|
|
|
|
|
** `by_type`
|
|
|
|
|
*** there are 2 additional fields accepted: `minOccurrence` and `maxOccurrence`.
|
|
|
|
|
** `by_command`
|
|
|
|
|
|
|
|
|
|
Consider the following example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy[tags=matchers,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_matchers.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
In the preceding example, you can see the dynamic portions of the contract in the
|
|
|
|
|
`matchers` sections. For the request part, you can see that, for all fields but
|
|
|
|
|
`valueWithoutAMatcher`, the values of the regular expressions that the stub should
|
|
|
|
|
@@ -784,6 +998,7 @@ If you're using asynchronous communication on the server side (your controllers
|
|
|
|
|
returning `Callable`, `DeferredResult`, and so on), then, inside your contract, you must
|
|
|
|
|
provide a `sync()` method in the `response` section. The following code shows an example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
org.springframework.cloud.contract.spec.Contract.make {
|
|
|
|
|
@@ -799,6 +1014,13 @@ org.springframework.cloud.contract.spec.Contract.make {
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
response:
|
|
|
|
|
async: true
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
=== Working with Context Paths
|
|
|
|
|
|
|
|
|
|
Spring Cloud Contract supports context paths.
|
|
|
|
|
@@ -871,11 +1093,18 @@ following sections explain the differences:
|
|
|
|
|
The output message can be triggered by calling a method (such as a `Scheduler` when a was
|
|
|
|
|
started and a message was sent), as shown in the following example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy]
|
|
|
|
|
----
|
|
|
|
|
include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=method_trigger,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_message_method.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
In the previous example case, the output message is sent to `output` if a method called
|
|
|
|
|
`bookReturnedTriggered` is executed. On the message *publisher's* side, we generate a
|
|
|
|
|
test that calls that method to trigger the message. On the *consumer* side, you can use
|
|
|
|
|
@@ -887,11 +1116,18 @@ the `some_label` to trigger the message.
|
|
|
|
|
The output message can be triggered by receiving a message, as shown in the following
|
|
|
|
|
example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy]
|
|
|
|
|
----
|
|
|
|
|
include::{tests_path}/samples-messaging-integration/src/test/groovy/com/example/IntegrationMessagingApplicationSpec.groovy[tags=message_trigger,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/contract_message_input_message.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
In the preceding example, the output message is sent to `output` if a proper message is
|
|
|
|
|
received on the `input` destination. On the message *publisher's* side, the engine
|
|
|
|
|
generates a test that sends the input message to the defined destination. On the
|
|
|
|
|
@@ -901,6 +1137,8 @@ generates a test that sends the input message to the defined destination. On the
|
|
|
|
|
[[contract-dsl-consumer-producer]]
|
|
|
|
|
==== Consumer/Producer
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL.
|
|
|
|
|
|
|
|
|
|
In HTTP, you have a notion of `client`/`stub and `server`/`test` notation. You can also
|
|
|
|
|
use those paradigms in messaging. In addition, Spring Cloud Contract Verifier also
|
|
|
|
|
provides the `consumer` and `producer` methods, as presented in the following example
|
|
|
|
|
@@ -915,21 +1153,28 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract
|
|
|
|
|
[[contract-dsl-common]]
|
|
|
|
|
==== Common
|
|
|
|
|
|
|
|
|
|
In the `input {}` or `outputMessage {}` section you can call `assertThat` with the name
|
|
|
|
|
In the `input` or `outputMessage` section you can call `assertThat` with the name
|
|
|
|
|
of a `method` (e.g. `assertThatMessageIsOnTheQueue()`) that you have defined in the
|
|
|
|
|
base class or in a static import. Spring Cloud Pipelines will execute that method
|
|
|
|
|
in the genertaed test.
|
|
|
|
|
base class or in a static import. Spring Cloud Contract will execute that method
|
|
|
|
|
in the generated test.
|
|
|
|
|
|
|
|
|
|
=== Multiple Contracts in One File
|
|
|
|
|
|
|
|
|
|
You can define multiple contracts in one file. Such a contract might resemble the
|
|
|
|
|
following example:
|
|
|
|
|
|
|
|
|
|
.Groovy DSL
|
|
|
|
|
[source,groovy,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy[lines=18..-1,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.YAML
|
|
|
|
|
[source,yml,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/yml/multiple_contracts.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
In the preceding example, one contract has the `name` field and the other does not. This
|
|
|
|
|
leads to generation of two tests that look more or less like this:
|
|
|
|
|
|
|
|
|
|
@@ -1001,6 +1246,8 @@ your tests far more meaningful.
|
|
|
|
|
|
|
|
|
|
== Customization
|
|
|
|
|
|
|
|
|
|
IMPORTANT: This section is valid only for Groovy DSL
|
|
|
|
|
|
|
|
|
|
You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
|
|
|
|
the remainder of this section.
|
|
|
|
|
|
|
|
|
|
@@ -1102,13 +1349,6 @@ can generate stubs for other HTTP server implementations).
|
|
|
|
|
|
|
|
|
|
=== Custom Contract Converter
|
|
|
|
|
|
|
|
|
|
Assume that your contract is written in a YAML file as follows:
|
|
|
|
|
|
|
|
|
|
[source,yml]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/contract.yml[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
The `ContractConverter` interface lets you register your own implementation of a contract
|
|
|
|
|
structure converter. The following code listing shows the `ContractConverter` interface:
|
|
|
|
|
|
|
|
|
|
@@ -1128,15 +1368,8 @@ The following example shows a typical `spring.factories` file:
|
|
|
|
|
|
|
|
|
|
[source]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/resources/META-INF/spring.factories[indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
The following example shows a typical YAML implementation that matches the preceding
|
|
|
|
|
example:
|
|
|
|
|
|
|
|
|
|
[source,groovy]
|
|
|
|
|
----
|
|
|
|
|
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy[indent=0,lines=16..-1]
|
|
|
|
|
org.springframework.cloud.contract.spec.ContractConverter=\
|
|
|
|
|
org.springframework.cloud.contract.verifier.converter.YamlContractConverter
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
==== Pact Converter
|
|
|
|
|
|