|
对于最新的稳定版本,请使用 spring-cloud-contract 5.0.0! |
消费者驱动合同(CDC)及生产方合同的逐步指南
举一个欺诈检测和贷款发放流程的例子。业务情景是我们想向人们发放贷款,但又不希望他们从中偷窃 我们。 我们现行的制度是向所有人发放贷款。
假设贷款发放是 的客户端欺诈检测服务器。 在当前的冲刺中,我们必须开发一个新功能:如果客户想借太多钱,我们会将客户标记为诈骗。
技术说明
-
欺诈检测具有
文物ID之http-server. -
贷款发行具有
文物ID之http-client. -
两者都有
群体识别之com.example. -
为了举例说明,以下
存根存储是Nexus/Artifactory。
社会评论
-
客户端和服务器开发团队都需要直接沟通,在流程中讨论变更。
-
CDC的核心是沟通。
服务器端代码可在 Spring Cloud Contract Samples 仓库中获取Samples/standalone/DSL/HTTP-Server而客户端代码则可在 Spring Cloud Contract 的仓库中获取Samples/standalone/DSL/HTTP-client路径。
| 在这种情况下,生产者拥有合同。从物理上看,所有合同都存在生产者的仓库中。 |
技术说明
重要提示:所有代码都可在 Spring Cloud Contract Samples 仓库中获取。
为了简化,我们使用以下缩写:
-
贷款发行(LI):HTTP 客户端
-
欺诈检测(FD):HTTP 服务器
-
SCC:春云合约
消费者方面(贷款发行)
作为贷款发行服务的开发者(欺诈检测服务器的使用者),你可以采取以下步骤:
-
开始做TDD时,先为你的特征写一个测试。
-
写出缺失的实现。
-
在本地克隆欺诈检测服务仓库。
-
在欺诈检测服务的本地仓库中定义合同。
-
添加 Spring Cloud Contract(SCC)插件。
-
运行集成测试。
-
提交拉取请求。
-
创建初步实施方案。
-
接手拉取请求。
-
写出缺失的实现。
-
部署你的应用。
-
在线工作。
我们从贷款发放流程开始,下面的UML图展示了:
写入缺失的实现
在某个时候,你需要向欺诈检测服务发送请求。 假设 你需要发送包含客户ID和客户想要借款金额的请求。你想发送给/fraudcheck通过使用放方法。 为此,你可以使用类似以下代码:
为了简化,欺诈检测服务的端口设置为8080, 以及应用程序运行于8090.
如果你从这个点开始测试,它就会出问题,因为端口上目前没有服务运行8080. |
本地克隆欺诈检测服务仓库
你可以先试试服务器端的合同。要做到这一点,你首先必须 通过运行以下命令克隆它:
$ git clone https://your-git-server.com/server-side.git local-http-server-repo
在欺诈检测服务的仓库中本地定义合同
作为消费者,你需要明确自己想要实现什么目标。你需要制定 你的期望。为此,请撰写以下合同:
将合同放入SRC/测试/资源/合同/欺诈文件夹。这欺诈文件夹
很重要,因为生产者的测试基类名称引用了该文件夹。 |
以下示例展示了我们的合同,涵盖Groovy和YAML:
YML合同相当直接。然而,当你查看合同时
你可能会好奇,用静态类型化的Groovy DSL编写value(client(...), server(...))部分是。使用此记号法,春云
契约允许你定义JSON块、URL或其他动态结构的部分。在
或者标识符或时间戳,你不需要硬编码一个值。你应该允许一些
不同的数值范围。要启用值范围,可以设置正则表达式
这与消费者的这些数值相符。你可以通过以下两种方式提供身体
映射符号或带有插值的字符串。我们强烈建议使用地图符号。
| 要设置契约,你必须理解地图符号。请查看Groovy关于JSON的文档。 |
前面所示的合同是双方之间的协议,满足:
-
如果发送HTTP请求时包含所有:
-
一个
放方法/fraudcheck端点 -
一个带有
client.id与正则表达式相匹配[0-9]{10}和贷款金额等于99999 -
一个
内容类型首部,值为application/vnd.fraud.v1+json
-
-
然后向消费者发送一个HTTP响应,使得
-
有地位
200 -
包含一个带有
欺诈检查状态包含欺诈和 这拒绝原因场的值为金额太高了 -
具有
内容类型首部,值为application/vnd.fraud.v1+json
-
一旦你准备好在集成测试中实际检查 API,你需要 本地安装存根。
添加 Spring Cloud 合约验证插件
我们可以添加 Maven 或 Gradle 插件。在这个例子中,我们展示了如何添加Maven。
首先,我们添加春云合约BOM,如下例子所示:
接着,添加春云合约验证器Maven插件,如下示例所示:
自从插件加入后,你得到的就是春云合约验证器特征,其中,
以下是所提供的合同:
-
生成并运行测试
-
制作和安装存根
你不想生成测试,因为作为消费者,你只想玩弄 存根。你需要跳过测试生成和调用。为此,运行以下命令:
$ cd local-http-server-repo
$ ./mvnw clean install -DskipTests
运行这些命令后,你应该会在日志中看到类似的内容:
[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
以下这句话极为重要:
[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 Cloud合同存根运行自动化功能
在 stub 下载时,你必须在你的消费者侧项目中完成以下作(贷款
应用服务):
-
添加
春云合约BOM的具体情况如下: -
将依赖添加于
春云合同存根跑者如下: -
在你的测试类中标注为
@AutoConfigureStubRunner.在注释中,提供群体识别和文物ID让Stub Runner下载你的stub 合作。 -
(可选)因为你是和合作者离线玩,你 也可以提供离线工作交换机(
StubRunnerProperties.StubsMode.LOCAL).
现在,当你运行测试时,日志中会看到类似这样的输出:
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.
生产者端(欺诈检测服务器)
作为欺诈检测服务器(贷款发行服务服务器)的开发者,你 你可能想:
-
接手拉取请求
-
写出缺失的实现
-
部署应用
下图展示了欺诈检测流程:
接管拉取请求
提醒一下,以下列表展示了初始实现过程:
然后你可以运行以下命令:
$ git checkout -b contract-change-pr master
$ git pull https://your-git-server.com/server-side-fork.git contract-change-pr
你必须添加自动生成测试所需的依赖关系,具体如下:
在 Maven 插件的配置中,你必须通过packageWithBaseClasses性质,具体如下:
本示例使用“基于约定”的命名,通过设置packageWithBaseClasses财产。这样做意味着最后两个包合并为
创建基础测试类的名称。在我们的案例中,合同是被放在SRC/测试/资源/合同/欺诈.因为你没有两个包,从
这合同文件夹,只选一个,应该是欺诈.添加基础后缀和
利用欺诈.这给了你欺诈基地考试班级名称。 |
所有生成的测试都会扩展这个类。在那里,你可以设置你的春季上下文
或者任何必要的事。在这种情况下,你应该使用Rest Assured MVC来实现
启动服务器端欺诈检测控制器.以下列表显示了欺诈基地类:
现在,如果你运行./mvnw 干净安装你会得到类似这样的输出:
Results :
Tests in error:
ContractVerifierTest.validate_shouldMarkClientAsFraud:32 » IllegalState Parsed...
这个错误发生是因为你有一个新的合同,从中生成了一个测试,并且 失败是因为你没有实现该功能。自动生成的测试看起来像 如下测试方法:
@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法,同样适用于匹配器各区段响应.
注意,在制作人那边,你也在做TDD。期望已表达
以测试的形式出现。该测试向我们自己的应用程序发送一个请求,地址为:
合同中定义了头部和正体。它还期望有精确定义的数值
在回应中。换句话说,你有红部分红,绿和重构.是时候将红进入绿.