消费者驱动合同(CDC)及生产方合同的逐步指南

以欺诈检测和贷款发放流程为例。业务 情况是我们想向人们发放贷款,但又不希望他们偷窃 我们。我们现行的制度是向所有人发放贷款。spring-doc.cadn.net.cn

假设贷款发放是 的客户端欺诈检测服务器。在当前 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

我们从贷款发放流程开始,下面的UML图展示了:spring-doc.cadn.net.cn

Getting-Started-CDC-client

通过为你的特征写测试开始做TDD

以下列表展示了我们可能用来检查贷款金额是否过高的测试 大:spring-doc.cadn.net.cn

假设你已经写好了新功能的测试。如果是大贷款申请 收到金额后,系统应会拒绝该贷款申请并附带说明。spring-doc.cadn.net.cn

写入缺失的实现

在某个时候,你需要向欺诈检测服务发送请求。假设 你需要发送包含客户ID和金额的请求 客户想借钱。你想把它发给/fraudcheck通过使用方法。 为此,你可以使用类似以下代码: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/测试/资源/合同/欺诈文件夹。这欺诈文件夹 很重要,因为生产者的测试基类名称引用了该文件夹。

以下示例展示了我们的合同,涵盖Groovy和YAML:spring-doc.cadn.net.cn

YML合同相当直接。然而,当你查看合同时 你可能会好奇,用静态类型化的Groovy DSL编写value(client(...), server(...))部分是。使用此记号法,春云 契约允许你定义JSON块、URL或其他动态结构的部分。在 或者标识符或时间戳,你不需要硬编码一个值。你应该允许一些 不同的数值范围。要启用值范围,可以设置正则表达式 这与消费者的这些数值相符。你可以通过以下两种方式提供身体 映射符号或带有插值的字符串。我们强烈建议使用地图符号。spring-doc.cadn.net.cn

要设置契约,你必须理解地图符号。请查看Groovy关于JSON的文档

前面所示的合同是双方之间的协议,满足:spring-doc.cadn.net.cn

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

添加 Spring Cloud 合约验证插件

我们可以添加 Maven 或 Gradle 插件。在这个例子中,我们展示了如何添加Maven。 首先,我们添加春云合约BOM,如下例子所示:spring-doc.cadn.net.cn

接着,添加春云合约验证器Maven插件,如下示例所示:spring-doc.cadn.net.cn

自从插件加入后,你得到的就是春云合约验证器特征,其中, 以下是所提供的合同: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合同存根运行自动化功能 在 stub 下载时,你必须在你的消费者侧项目中完成以下作(贷款 应用服务):spring-doc.cadn.net.cn

  1. 添加春云合约BOM的具体情况如下:spring-doc.cadn.net.cn

  2. 将依赖添加于春云合同存根跑者如下:spring-doc.cadn.net.cn

  3. 在你的测试类中标注为@AutoConfigureStubRunner.在注释中,提供群体识别文物ID让Stub Runner下载你的stub 合作。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}]

这个输出意味着 Stub Runner 找到了你的 stub,并为你的应用启动了服务器 组ID 为com.example以及一个伪影IDhttp-server版本0.0.1-快照之 小作品和存根端口上的分类器8080.spring-doc.cadn.net.cn

提交拉取请求

你迄今为止所做的是一个迭代过程。你可以尝试 签合同,本地安装,然后在消费者端工作,直到合同生效为止 你想得美。spring-doc.cadn.net.cn

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

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

作为欺诈检测服务器(贷款发行服务服务器)的开发者,你 你可能想:spring-doc.cadn.net.cn

下图展示了欺诈检测流程:spring-doc.cadn.net.cn

Getting-started-CDC-Server

接管拉取请求

提醒一下,以下列表展示了初始实现过程: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/测试/资源/合同/欺诈.因为你没有两个包,从 这合同文件夹,只选一个,应该是欺诈.添加基础后缀和 利用欺诈.这给了你欺诈基地考试班级名称。

所有生成的测试都会扩展这个类。在那里,你可以设置你的春季上下文 或者任何必要的事。在这种情况下,你应该使用Rest Assured MVC来实现 启动服务器端欺诈检测控制器.以下列表显示了欺诈基地类:spring-doc.cadn.net.cn

现在,如果你运行./mvnw 干净安装你会得到类似这样的输出: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,你可以看到所有制作人()合同中包含的部分价值(消费者......)、生产者(......))测试中注入了模块。 如果你用YAML法,同样适用于匹配器各区段响应.spring-doc.cadn.net.cn

注意,在制作人那边,你也在做TDD。期望已表达 以测试的形式出现。该测试向我们自己的应用程序发送一个请求,地址为: 合同中定义了头部和正体。它还期望有精确定义的数值 在回应中。换句话说,你有部分,绿重构.是时候将进入绿.spring-doc.cadn.net.cn

写入缺失的实现

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

当你奔跑时./mvnw 干净安装测试再次通过。自春云以来 Contract Verifier 插件将测试添加到生成测试源您可以 实际上,在你的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 干净部署,这会同时发布 申请和存根伪影。spring-doc.cadn.net.cn

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

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

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

Getting-started-CDC-client-final

将分支合并为主

以下命令展示了一种将分支合并为主文件的方法:spring-doc.cadn.net.cn

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

在线工作

现在你可以禁用 Spring Cloud Contract Stub Runner 的离线工作,并表示 存放你存根的仓库所在的位置。此刻,服务器的残余 侧面会自动从 Nexus/Artifactory 下载。你可以设置 的值小作品模式远程.以下代码展示了一个示例 通过改变属性实现同样的效果:spring-doc.cadn.net.cn

就是这样。你已经完成了教程。spring-doc.cadn.net.cn