|
|
|
|
@@ -28,7 +28,6 @@ Spring Cloud Contract Verifier stand out on the market of Consumer Driven Contra
|
|
|
|
|
- Automatic generation of tests from the defined contract.
|
|
|
|
|
- Stub Runner functionality: The stubs are automatically downloaded at runtime from Nexus or Artifactory.
|
|
|
|
|
- Spring Cloud integration: No discovery service is needed for integration tests.
|
|
|
|
|
- Spring Cloud Contract integrates with Pact and provides easy hooks to extend its functionality.
|
|
|
|
|
- Ability to add support for any language & framework through Docker.
|
|
|
|
|
|
|
|
|
|
[[how-to-not-write-contracts-in-groovy]]
|
|
|
|
|
@@ -831,427 +830,6 @@ to find stub definitions and contracts. For example, for `com.example:foo:1.0.0`
|
|
|
|
|
* Stub servers are started and fed with mappings.
|
|
|
|
|
* Messaging definitions are read and used in the messaging tests.
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker]]
|
|
|
|
|
== How Can I Use the Pact Broker?
|
|
|
|
|
|
|
|
|
|
When using https://pact.io/[Pact], you can use the https://github.com/pact-foundation/pact_broker[Pact Broker]
|
|
|
|
|
to store and share Pact definitions. Starting from Spring Cloud Contract
|
|
|
|
|
2.0.0, you can fetch Pact files from the Pact Broker to generate
|
|
|
|
|
tests and stubs.
|
|
|
|
|
|
|
|
|
|
IMPORTANT: Pact follows the consumer contract convention. That means
|
|
|
|
|
that the consumer creates the Pact definitions first and then
|
|
|
|
|
shares the files with the Producer. Those expectations are generated
|
|
|
|
|
from the Consumer's code and can break the Producer if the expectations
|
|
|
|
|
are not met.
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker-pact]]
|
|
|
|
|
=== How to Work with Pact
|
|
|
|
|
|
|
|
|
|
Spring Cloud Contract includes support for the https://docs.pact.io/[Pact] representation of
|
|
|
|
|
contracts up until version 4. Instead of using the DSL, you can use Pact files. In this section, we
|
|
|
|
|
show how to add Pact support for your project. Note, however, that not all functionality is supported.
|
|
|
|
|
Starting with version 3, you can combine multiple matchers for the same element:
|
|
|
|
|
You can use matchers for the body, headers, request and path, and you can use value generators.
|
|
|
|
|
Spring Cloud Contract currently only supports multiple matchers that are combined by using the `AND` rule logic.
|
|
|
|
|
Next to that, the request and path matchers are skipped during the conversion.
|
|
|
|
|
When using a date, time, or datetime value generator with a given format,
|
|
|
|
|
the given format is skipped and the ISO format is used.
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker-pact-converter]]
|
|
|
|
|
=== Pact Converter
|
|
|
|
|
|
|
|
|
|
In order to properly support the Spring Cloud Contract way of doing messaging
|
|
|
|
|
with Pact, you have to provide some additional metadata entries.
|
|
|
|
|
|
|
|
|
|
To define the destination to which a message gets sent, you have to
|
|
|
|
|
set a `metaData` entry in the Pact file with the `sentTo` key equal to the destination to
|
|
|
|
|
which a message is to be sent (for example, `"metaData": { "sentTo": "activemq:output" }`).
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker-pact-contract]]
|
|
|
|
|
=== Pact Contract
|
|
|
|
|
|
|
|
|
|
Spring Cloud Contract can read the Pact JSON definition. You can place the file in the
|
|
|
|
|
`src/test/resources/contracts` folder. Remember to put the `spring-cloud-contract-pact` dependency to your classpath.
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker-pact-for-producers]]
|
|
|
|
|
=== Pact for Producers
|
|
|
|
|
|
|
|
|
|
On the producer side, you must add two additional dependencies to your plugin
|
|
|
|
|
configuration. One is the Spring Cloud Contract Pact support, and the other represents
|
|
|
|
|
the current Pact version that you use. The following listing shows how to do so for both
|
|
|
|
|
Maven and Gradle:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
|
|
|
|
.Maven
|
|
|
|
|
----
|
|
|
|
|
include::{standalone_pact_path}/producer_pact/pom.xml[tags=pact_dependency,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
|
|
|
|
.Gradle
|
|
|
|
|
----
|
|
|
|
|
include::{standalone_pact_path}/producer_pact/build.gradle[tags=pact_dependency,indent=0]
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
When you build your application, a test and stub is generated. The following
|
|
|
|
|
example shows a test and stub that came from this process:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
|
|
|
|
|
.test
|
|
|
|
|
----
|
|
|
|
|
@Test
|
|
|
|
|
public void validate_shouldMarkClientAsFraud() throws Exception {
|
|
|
|
|
// given:
|
|
|
|
|
MockMvcRequestSpecification request = given()
|
|
|
|
|
.header("Content-Type", "application/vnd.fraud.v1+json")
|
|
|
|
|
.body("{\"clientId\":\"1234567890\",\"loanAmount\":99999}");
|
|
|
|
|
|
|
|
|
|
// when:
|
|
|
|
|
ResponseOptions response = given().spec(request)
|
|
|
|
|
.put("/fraudcheck");
|
|
|
|
|
|
|
|
|
|
// then:
|
|
|
|
|
assertThat(response.statusCode()).isEqualTo(200);
|
|
|
|
|
assertThat(response.header("Content-Type")).matches("application/vnd\\.fraud\\.v1\\+json.*");
|
|
|
|
|
// and:
|
|
|
|
|
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
|
|
|
|
|
assertThatJson(parsedJson).field("['rejectionReason']").isEqualTo("Amount too high");
|
|
|
|
|
// and:
|
|
|
|
|
assertThat(parsedJson.read("$.fraudCheckStatus", String.class)).matches("FRAUD");
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[source,json,indent=0,subs="verbatim,attributes",role="secondary"]
|
|
|
|
|
.stub
|
|
|
|
|
----
|
|
|
|
|
{
|
|
|
|
|
"id" : "996ae5ae-6834-4db6-8fac-358ca187ab62",
|
|
|
|
|
"uuid" : "996ae5ae-6834-4db6-8fac-358ca187ab62",
|
|
|
|
|
"request" : {
|
|
|
|
|
"url" : "/fraudcheck",
|
|
|
|
|
"method" : "PUT",
|
|
|
|
|
"headers" : {
|
|
|
|
|
"Content-Type" : {
|
|
|
|
|
"matches" : "application/vnd\\.fraud\\.v1\\+json.*"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"bodyPatterns" : [ {
|
|
|
|
|
"matchesJsonPath" : "$[?(@.['loanAmount'] = 99999)]"
|
|
|
|
|
}, {
|
|
|
|
|
"matchesJsonPath" : "$[?(@.clientId =~ /([0-9]{10})/)]"
|
|
|
|
|
} ]
|
|
|
|
|
},
|
|
|
|
|
"response" : {
|
|
|
|
|
"status" : 200,
|
|
|
|
|
"body" : "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}",
|
|
|
|
|
"headers" : {
|
|
|
|
|
"Content-Type" : "application/vnd.fraud.v1+json;charset=UTF-8"
|
|
|
|
|
},
|
|
|
|
|
"transformers" : [ "response-template" ]
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
[[how-to-use-pact-broker-pact-consumers]]
|
|
|
|
|
=== Pact for Consumers
|
|
|
|
|
|
|
|
|
|
On the consumer side, you must add two additional dependencies to your project
|
|
|
|
|
dependencies. One is the Spring Cloud Contract Pact support, and the other represents the
|
|
|
|
|
current Pact version that you use. The following listing shows how to do so for both
|
|
|
|
|
Maven and Gradle:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
|
|
|
|
|
.Maven
|
|
|
|
|
----
|
|
|
|
|
include::{standalone_pact_path}/consumer_pact_stubrunner/pom.xml[tags=pact_dependency,indent=0]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
|
|
|
|
|
.Gradle
|
|
|
|
|
----
|
|
|
|
|
include::{standalone_pact_path}/consumer_pact_stubrunner/build.gradle[tags=pact_dependency,indent=0]
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
[[pact-stub-downloader]]
|
|
|
|
|
=== Communicating with the Pact Broker
|
|
|
|
|
|
|
|
|
|
Whenever the `repositoryRoot` property starts with a Pact protocol
|
|
|
|
|
(that is, starts with `pact://`), the stub downloader tries
|
|
|
|
|
to fetch the Pact contract definitions from the Pact Broker.
|
|
|
|
|
Whatever is set after `pact://` is parsed as the Pact Broker URL.
|
|
|
|
|
|
|
|
|
|
By setting environment variables, system properties, or properties set
|
|
|
|
|
inside the plugin or contracts repository configuration, you can
|
|
|
|
|
tweak the downloader's behavior. The following table describes the
|
|
|
|
|
properties:
|
|
|
|
|
|
|
|
|
|
.Pact Stub Downloader properties
|
|
|
|
|
|====
|
|
|
|
|
|Name of a property |Default | Description
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.host` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.host` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_HOST` (env prop)
|
|
|
|
|
|Host from URL passed to `repositoryRoot`
|
|
|
|
|
|The URL of the Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.port` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.port` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_PORT` (env prop)
|
|
|
|
|
|Port from URL passed to `repositoryRoot`
|
|
|
|
|
|The port of Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.protocol` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.protocol` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_PROTOCOL` (env prop)
|
|
|
|
|
|Protocol from URL passed to `repositoryRoot`
|
|
|
|
|
|The protocol of Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.tags` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.tags` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_TAGS` (env prop)
|
|
|
|
|
|Version of the stub, or `latest` if version is `+`
|
|
|
|
|
|The tags that should be used to fetch the stub.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.auth.scheme` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.auth.scheme` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_SCHEME` (env prop)
|
|
|
|
|
|`Basic`
|
|
|
|
|
|The kind of authentication that should be used to connect to the Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.auth.username` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.auth.username` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_USERNAME` (env prop)
|
|
|
|
|
|The username passed to `contractsRepositoryUsername` (Maven) or `contractRepository.username` (Gradle)
|
|
|
|
|
|The username to use when connecting to the Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.auth.password` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.auth.password` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_AUTH_PASSWORD` (env prop)
|
|
|
|
|
|The password passed to `contractsRepositoryPassword` (Maven) or `contractRepository.password` (Gradle)
|
|
|
|
|
|The password to use when connecting to the Pact Broker.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `pactbroker.provider-name-with-group-id` (plugin prop)
|
|
|
|
|
|
|
|
|
|
* `stubrunner.properties.pactbroker.provider-name-with-group-id` (system prop)
|
|
|
|
|
|
|
|
|
|
* `STUBRUNNER_PROPERTIES_PACTBROKER_PROVIDER_NAME_WITH_GROUP_ID` (env prop)
|
|
|
|
|
|false
|
|
|
|
|
|When `true`, the provider name is a combination of `groupId:artifactId`. If `false`, only `artifactId` is used.
|
|
|
|
|
|====
|
|
|
|
|
|
|
|
|
|
[[how-to-pact-consumer]]
|
|
|
|
|
=== Flow: Consumer Contract Approach with Pact Broker on the Consumer Side
|
|
|
|
|
|
|
|
|
|
The consumer uses the Pact framework to generate Pact files. The
|
|
|
|
|
Pact files are sent to the Pact Broker. You can find an example of such a setup
|
|
|
|
|
https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact[here].
|
|
|
|
|
|
|
|
|
|
[[how-to-pact-producer]]
|
|
|
|
|
=== Flow: Consumer Contract Approach with Pact Broker on the Producer Side
|
|
|
|
|
|
|
|
|
|
For the producer to use the Pact files from the Pact Broker, we can reuse the
|
|
|
|
|
same mechanism we use for external contracts. We route Spring Cloud Contract
|
|
|
|
|
to use the Pact implementation with the URL that contains
|
|
|
|
|
the `pact://` protocol. You can pass the URL to the
|
|
|
|
|
Pact Broker. You can find an example of such a setup
|
|
|
|
|
https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/producer_pact[here].
|
|
|
|
|
The following listing shows the configuration details for both Maven and Gradle:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,xml,indent=0,role="primary"]
|
|
|
|
|
.Maven
|
|
|
|
|
----
|
|
|
|
|
<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>pact://http://localhost:8085</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>
|
|
|
|
|
<!-- When + is passed, a latest tag will be applied when fetching pacts -->
|
|
|
|
|
<version>+</version>
|
|
|
|
|
</contractDependency>
|
|
|
|
|
|
|
|
|
|
<!-- The contracts mode can't be classpath -->
|
|
|
|
|
<contractsMode>REMOTE</contractsMode>
|
|
|
|
|
</configuration>
|
|
|
|
|
<!-- Don't forget to add spring-cloud-contract-pact to the classpath! -->
|
|
|
|
|
<dependencies>
|
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>org.springframework.cloud</groupId>
|
|
|
|
|
<artifactId>spring-cloud-contract-pact</artifactId>
|
|
|
|
|
<version>${spring-cloud-contract.version}</version>
|
|
|
|
|
</dependency>
|
|
|
|
|
</dependencies>
|
|
|
|
|
</plugin>
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[source,groovy,indent=0,role="secondary"]
|
|
|
|
|
.Gradle
|
|
|
|
|
----
|
|
|
|
|
buildscript {
|
|
|
|
|
repositories {
|
|
|
|
|
//...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dependencies {
|
|
|
|
|
// ...
|
|
|
|
|
// Don't forget to add spring-cloud-contract-pact to the classpath!
|
|
|
|
|
classpath "org.springframework.cloud:spring-cloud-contract-pact:${contractVersion}"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
contracts {
|
|
|
|
|
// When + is passed, a latest tag will be applied when fetching pacts
|
|
|
|
|
contractDependency {
|
|
|
|
|
stringNotation = "${project.group}:${project.name}:+"
|
|
|
|
|
}
|
|
|
|
|
contractRepository {
|
|
|
|
|
repositoryUrl = "pact://http://localhost:8085"
|
|
|
|
|
}
|
|
|
|
|
// The mode can't be classpath
|
|
|
|
|
contractsMode = "REMOTE"
|
|
|
|
|
// Base class mappings etc.
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
With such a setup:
|
|
|
|
|
|
|
|
|
|
* Pact files are downloaded from the Pact Broker.
|
|
|
|
|
* Spring Cloud Contract converts the Pact files into tests and stubs.
|
|
|
|
|
* The JAR with the stubs gets automatically created, as usual.
|
|
|
|
|
|
|
|
|
|
[[how-to-pact-consumer-producer-contract]]
|
|
|
|
|
=== Flow: Producer Contract Approach with Pact on the Consumer Side
|
|
|
|
|
|
|
|
|
|
In the scenario where you do not want to do the consumer contract approach
|
|
|
|
|
(for every single consumer, define the expectations) but you prefer
|
|
|
|
|
to do producer contracts (the producer provides the contracts and
|
|
|
|
|
publishes stubs), you can use Spring Cloud Contract with the
|
|
|
|
|
Stub Runner option. You can find an example of such a setup
|
|
|
|
|
https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/{samples_branch}/consumer_pact_stubrunner[here].
|
|
|
|
|
|
|
|
|
|
Remember to add the Stub Runner and Spring Cloud Contract Pact modules
|
|
|
|
|
as test dependencies.
|
|
|
|
|
|
|
|
|
|
The following listing shows the configuration details for both Maven and Gradle:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,xml,indent=0,role="primary"]
|
|
|
|
|
.Maven
|
|
|
|
|
----
|
|
|
|
|
<dependencyManagement>
|
|
|
|
|
<dependencies>
|
|
|
|
|
<dependency>
|
|
|
|
|
<groupId>org.springframework.cloud</groupId>
|
|
|
|
|
<artifactId>spring-cloud-dependencies</artifactId>
|
|
|
|
|
<version>${spring-cloud.version}</version>
|
|
|
|
|
<type>pom</type>
|
|
|
|
|
<scope>import</scope>
|
|
|
|
|
</dependency>
|
|
|
|
|
</dependencies>
|
|
|
|
|
</dependencyManagement>
|
|
|
|
|
|
|
|
|
|
<!-- Don't forget to add spring-cloud-contract-pact to the classpath! -->
|
|
|
|
|
<dependencies>
|
|
|
|
|
<!-- ... -->
|
|
|
|
|
<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-contract-pact</artifactId>
|
|
|
|
|
<scope>test</scope>
|
|
|
|
|
</dependency>
|
|
|
|
|
</dependencies>
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
[source,groovy,indent=0,role="secondary"]
|
|
|
|
|
.Gradle
|
|
|
|
|
----
|
|
|
|
|
dependencyManagement {
|
|
|
|
|
imports {
|
|
|
|
|
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dependencies {
|
|
|
|
|
//...
|
|
|
|
|
testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner")
|
|
|
|
|
// Don't forget to add spring-cloud-contract-pact to the classpath!
|
|
|
|
|
testCompile("org.springframework.cloud:spring-cloud-contract-pact")
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
Next, you can pass the URL of the Pact Broker to `repositoryRoot`, prefixed
|
|
|
|
|
with the `pact://` protocol (for example, `pact://http://localhost:8085`), as the following
|
|
|
|
|
example shows:
|
|
|
|
|
|
|
|
|
|
====
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@RunWith(SpringRunner.class)
|
|
|
|
|
@SpringBootTest
|
|
|
|
|
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
|
|
|
|
ids = "com.example:beer-api-producer-pact",
|
|
|
|
|
repositoryRoot = "pact://http://localhost:8085")
|
|
|
|
|
public class BeerControllerTest {
|
|
|
|
|
//Inject the port of the running stub
|
|
|
|
|
@StubRunnerPort("beer-api-producer-pact") int producerPort;
|
|
|
|
|
//...
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
With such a setup:
|
|
|
|
|
|
|
|
|
|
* Pact files are downloaded from the Pact Broker.
|
|
|
|
|
* Spring Cloud Contract converts the Pact files into stub definitions.
|
|
|
|
|
* The stub servers are started and fed with stubs.
|
|
|
|
|
|
|
|
|
|
[[how-to-debug]]
|
|
|
|
|
== How Can I Debug the Request/Response Being Sent by the Generated Tests Client?
|
|
|
|
|
|
|
|
|
|
|