对于最新的稳定版本,请使用 spring-cloud-contract 4.3.0spring-doc.cadn.net.cn

消费者驱动合同 (CDC) 分步指南,生产方合同

考虑欺诈检测和贷款发放流程的示例。业务 我们想向人们发放贷款,但又不希望他们从中窃取贷款 我们。我们系统目前的实施向每个人提供贷款。spring-doc.cadn.net.cn

假设Loan IssuanceFraud Detection服务器。在当前 sprint,我们必须开发一个新功能:如果客户想借太多钱, 我们将客户标记为欺诈者。spring-doc.cadn.net.cn

服务器端代码可在 Spring Cloud Contract Samples 存储库下找到samples/standalone/dsl/http-server路径,客户端代码在 Spring Cloud Contract 的存储库下可用samples/standalone/dsl/http-client路径。spring-doc.cadn.net.cn

在这种情况下,生产者拥有合同。从物理上讲,所有合同都是 在生产者的存储库中。

技术说明

重要提示:所有代码都可以在 spring Cloud Contract Samples 存储库下获得。spring-doc.cadn.net.cn

为简单起见,我们使用以下首字母缩略词:spring-doc.cadn.net.cn

消费者方面(贷款发放)

作为贷款发放服务的开发人员(欺诈检测服务器的使用者),您可以执行以下步骤:spring-doc.cadn.net.cn

  1. 通过为您的功能编写测试来开始执行 TDD。spring-doc.cadn.net.cn

  2. 编写缺少的实现。spring-doc.cadn.net.cn

  3. 在本地克隆欺诈检测服务存储库。spring-doc.cadn.net.cn

  4. 在欺诈检测服务的存储库中本地定义合同。spring-doc.cadn.net.cn

  5. 添加 Spring Cloud Contract (SCC) 插件。spring-doc.cadn.net.cn

  6. 运行集成测试。spring-doc.cadn.net.cn

  7. 提交拉取请求。spring-doc.cadn.net.cn

  8. 创建初始实现。spring-doc.cadn.net.cn

  9. 接管拉取请求。spring-doc.cadn.net.cn

  10. 编写缺少的实现。spring-doc.cadn.net.cn

  11. 部署您的应用程序。spring-doc.cadn.net.cn

  12. 在线工作。spring-doc.cadn.net.cn

我们从贷款发放流程开始,如下图所示:spring-doc.cadn.net.cn

开始 cdc 客户端

通过为您的功能编写测试来开始执行 TDD

以下列表显示了一个测试,我们可能会用它来检查贷款金额是否太过 大:spring-doc.cadn.net.cn

假设你已经编写了新功能的测试。如果贷款申请大额 收到金额时,系统应拒绝该贷款申请并附上一些描述。spring-doc.cadn.net.cn

编写缺失的实现

在某个时间点,您需要向欺诈检测服务发送请求。假设 您需要发送包含客户端 ID 和金额的请求 客户想借。您想将其发送到/fraudcheckURL 的PUT方法。 为此,可以使用类似于以下内容的代码:spring-doc.cadn.net.cn

为简单起见,欺诈检测服务的端口设置为8080和 应用程序运行在8090.spring-doc.cadn.net.cn

如果此时启动测试,它会中断,因为当前没有服务在端口上运行8080.

在本地克隆欺诈检测服务存储库

您可以从尝试服务器端合约开始。为此,您必须首先 通过运行以下命令来克隆它:spring-doc.cadn.net.cn

$ git clone https://your-git-server.com/server-side.git local-http-server-repo

在欺诈检测服务的存储库中本地定义合同

作为消费者,您需要定义您到底想要实现什么。你需要制定你的期望。为此,请编写以下合同:spring-doc.cadn.net.cn

将合约放在src/test/resources/contracts/fraud文件夹。 这fraud文件夹 很重要,因为生产者的测试基类名称引用了该文件夹。

以下示例显示了我们的合约,在 Groovy 和 YAML 中:spring-doc.cadn.net.cn

YML 合约非常简单。但是,当您查看合同时 使用静态类型的 Groovy DSL 编写,您可能想知道value(client(…​), server(…​))零件是。通过使用这种表示法,Spring Cloud Contract 允许您定义 JSON 块、URL 或其他动态结构的各个部分。在这种情况下 标识符或时间戳,则无需对值进行硬编码。您想允许一些 不同的值范围。要启用值范围,您可以设置正则表达式 与使用者端的这些值匹配。您可以通过以下任一方式提供身体 映射表示法或带有插值的字符串。我们强烈建议使用地图表示法。spring-doc.cadn.net.cn

要设置合同,您必须了解地图表示法。请参阅有关 JSON 的 Groovy 文档

前面显示的合同是双方之间的协议,包括:spring-doc.cadn.net.cn

准备好在集成测试中实际检查 API 后,您需要 在本地安装存根。spring-doc.cadn.net.cn

添加 Spring Cloud Contract Verifier 插件

我们可以添加 Maven 或 Gradle 插件。在此示例中,我们展示了如何添加 Maven。 首先,我们将Spring Cloud ContractBOM,如以下示例所示:spring-doc.cadn.net.cn

接下来,将Spring Cloud Contract VerifierMaven 插件,如以下示例所示:spring-doc.cadn.net.cn

由于添加了插件,您将获得Spring Cloud Contract Verifier功能,其中,从提供的合同中:spring-doc.cadn.net.cn

您不想生成测试,因为您作为消费者只想玩 存根。您需要跳过测试生成和调用。为此,请运行以下命令:spring-doc.cadn.net.cn

$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests

运行这些命令后,您应该在日志中看到类似以下内容的内容:spring-doc.cadn.net.cn

[INFO] --- spring-cloud-contract-maven-plugin:1.0.0.BUILD-SNAPSHOT:generateStubs (default-generateStubs) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar
[INFO]
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ http-server ---
[INFO] Building jar: /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:1.5.5.BUILD-SNAPSHOT:repackage (default) @ http-server ---
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ http-server ---
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.jar
[INFO] Installing /some/path/http-server/pom.xml to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT.pom
[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

以下行非常重要:spring-doc.cadn.net.cn

[INFO] Installing /some/path/http-server/target/http-server-0.0.1-SNAPSHOT-stubs.jar to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar

它确认http-server已安装在本地 存储 库。spring-doc.cadn.net.cn

运行集成测试

为了从 Spring Cloud Contract Stub Runner 的自动功能中获利 存根下载时,您必须在消费者端项目 (Loan Application service):spring-doc.cadn.net.cn

  1. 添加Spring Cloud ContractBOM,如下所示:spring-doc.cadn.net.cn

  2. 将依赖项添加到Spring Cloud Contract Stub Runner如下:spring-doc.cadn.net.cn

  3. 使用@AutoConfigureStubRunner.在注释中,提供group-idartifact-id让存根运行器下载您的存根 合作。spring-doc.cadn.net.cn

  4. (可选)因为您离线与协作者一起玩,所以您 还可以提供离线工作开关(StubRunnerProperties.StubsMode.LOCAL).spring-doc.cadn.net.cn

现在,当您运行测试时,您会在日志中看到类似以下内容的输出:spring-doc.cadn.net.cn

2016-07-19 14:22:25.403  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Desired version is + - will try to resolve the latest version
2016-07-19 14:22:25.438  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved version is 0.0.1-SNAPSHOT
2016-07-19 14:22:25.439  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolving artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT using remote repositories []
2016-07-19 14:22:25.451  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Resolved artifact com.example:http-server:jar:stubs:0.0.1-SNAPSHOT to /path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar
2016-07-19 14:22:25.465  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacking stub from JAR [URI: file:/path/to/your/.m2/repository/com/example/http-server/0.0.1-SNAPSHOT/http-server-0.0.1-SNAPSHOT-stubs.jar]
2016-07-19 14:22:25.475  INFO 41050 --- [           main] o.s.c.c.stubrunner.AetherStubDownloader  : Unpacked file to [/var/folders/0p/xwq47sq106x1_g3dtv6qfm940000gq/T/contracts100276532569594265]
2016-07-19 14:22:27.737  INFO 41050 --- [           main] o.s.c.c.stubrunner.StubRunnerExecutor    : All stubs are now running RunningStubs [namesAndPorts={com.example:http-server:0.0.1-SNAPSHOT:stubs=8080}]

此输出意味着存根运行程序已找到存根并为应用程序启动服务器 组 ID 为com.example项目 ID 为http-server带版本0.0.1-SNAPSHOT之 存根和stubs端口上的分类器8080.spring-doc.cadn.net.cn

提交拉取请求

到目前为止,你所做的是一个迭代过程。你可以尝试一下contract,在本地安装它,并在消费者端工作,直到合约像你希望的那样工作。spring-doc.cadn.net.cn

对结果感到满意并且测试通过后,可以将拉取请求发布到 服务器端。目前,消费者方面的工作已经完成。spring-doc.cadn.net.cn

生产者端(欺诈检测服务器)

作为欺诈检测服务器(贷款发放服务的服务器)的开发人员,您 可能想要:spring-doc.cadn.net.cn

以下 UML 图显示了欺诈检测流:spring-doc.cadn.net.cn

开始 cdc 服务器

接管拉取请求

提醒一下,以下列表显示了初始实现:spring-doc.cadn.net.cn

然后,您可以运行以下命令:spring-doc.cadn.net.cn

$ git checkout -b contract-change-pr master
$ git pull https://your-git-server.com/server-side-fork.git contract-change-pr

必须添加自动生成的测试所需的依赖项,如下所示:spring-doc.cadn.net.cn

在 Maven 插件的配置中,必须将packageWithBaseClasses属性,如下所示:spring-doc.cadn.net.cn

此示例通过设置packageWithBaseClasses财产。这样做意味着最后两个包组合为 创建基测试类的名称。在我们的案例中,合同是根据src/test/resources/contracts/fraud.由于您没有两个从 这contracts文件夹,只选择一个,它应该是fraud.添加Basesuffix 和 利用fraud.这给了你FraudBase测试类名称。

所有生成的测试都扩展了该类。在那里,您可以设置 Spring Context 或任何必要的。在这种情况下,您应该使用 Rest Assured MVC 来 启动服务器端FraudDetectionController.以下列表显示了FraudBase类:spring-doc.cadn.net.cn

现在,如果您运行./mvnw clean install,您将得到类似于以下输出的内容:spring-doc.cadn.net.cn

Results :

Tests in error:
  ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...

发生此错误的原因是,您有一个从中生成测试的新协定,并且它 失败,因为您尚未实现该功能。自动生成的测试将看起来 像下面的测试方法:spring-doc.cadn.net.cn

@Test
public void validate_shouldMarkClientAsFraud() throws Exception {
    // given:
        MockMvcRequestSpecification request = given()
                .header("Content-Type", "application/vnd.fraud.v1+json")
                .body("{\"client.id\":\"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("['fraudCheckStatus']").matches("[A-Z]{5}");
        assertThatJson(parsedJson).field("['rejection.reason']").isEqualTo("Amount too high");
}

如果您使用 Groovy DSL,您可以看到所有producer()合同中存在的部分value(consumer(…​), producer(…​))块被注入到测试中。 如果您使用 YAML,则这同样适用于matchers部分response.spring-doc.cadn.net.cn

请注意,在生产者端,您也在做 TDD。表达了期望 以测试的形式。此测试向我们自己的应用程序发送一个请求,其中包含 URL headers 和合约中定义的正文。它还需要精确定义的值 在回应中。换句话说,你有red部分red,greenrefactor.是时候将red进入green.spring-doc.cadn.net.cn

编写缺失的实现

因为你知道预期的输入和预期的输出,所以你可以写缺失的 实现如下:spring-doc.cadn.net.cn

当你运行时./mvnw clean install再次,测试通过了。自 Spring Cloud 以来 Contract Verifier 插件将测试添加到generated-test-sources您可以 实际从您的 IDE 运行这些测试。spring-doc.cadn.net.cn

部署您的应用程序

完成工作后,您可以部署更改。为此,您必须首先合并 分支,运行以下命令:spring-doc.cadn.net.cn

$ git checkout master
$ git merge --no-ff contract-change-pr
$ git push origin master

您的 CI 可能会运行一个命令,例如./mvnw clean deploy,这将同时发布 应用程序和存根工件。spring-doc.cadn.net.cn

消费者方(贷款发放),最后一步

作为贷款发放服务的开发人员(欺诈检测服务器的使用者),您需要:spring-doc.cadn.net.cn

以下 UML 图显示了进程的最终状态:spring-doc.cadn.net.cn

开始-cdc-client-final

将分支合并到主分支

以下命令显示了使用 Git 将分支合并到 master 中的一种方法:spring-doc.cadn.net.cn

$ git checkout master
$ git merge --no-ff contract-change-pr

在线工作

现在您可以禁用 Spring Cloud Contract Stub Runner 的离线工作,并指示 包含存根的存储库所在的位置。此时,服务器的存根 side 会自动从 Nexus/Artifactory 下载。您可以设置stubsModeREMOTE.以下代码显示了 通过更改属性来实现相同的效果:spring-doc.cadn.net.cn

就是这样。您已完成本教程。spring-doc.cadn.net.cn