此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 spring-cloud-contract 4.1.5! |
包含生产者端合同的消费者驱动型合同 (CDC) 分步指南
考虑欺诈检测和贷款发放流程的示例。业务 情况是这样的,我们想向人们发放贷款,但不希望他们从 我们。我们系统的当前实施向所有人提供贷款。
假设它是服务器的客户端。在当前的
sprint,我们必须开发一个新功能:如果客户想借太多钱,
我们将客户标记为欺诈者。Loan Issuance
Fraud Detection
技术说明
-
欺诈检测具有 。
artifact-id
http-server
-
贷款发行有一个 。
artifact-id
http-client
-
两者都有 .
group-id
com.example
-
在此示例中,为 Nexus/Artifactory。
Stub Storage
社会评论
-
客户端和服务器开发团队都需要直接沟通,并且 在完成该过程时讨论更改。
-
CDC 是关于沟通的。
服务器端代码位于 Spring Cloud Contract Samples 存储库路径下,客户端代码位于 Spring Cloud Contract 的存储库路径下。samples/standalone/dsl/http-server
samples/standalone/dsl/http-client
在这种情况下,生产商拥有合同。从物理上讲,所有的合同都是 在生产者的存储库中。 |
技术说明
重要提示:所有代码都可以在 spring Cloud Contract Samples repo 下找到。
为简单起见,我们使用以下首字母缩略词:
-
贷款发放 (LI):HTTP 客户端
-
欺诈检测 (FD):HTTP 服务器
-
SCC:Spring Cloud Contract
消费者方面(贷款发放)
作为 Loan Issuance 服务的开发人员(Fraud Detection 服务器的使用者),您可以执行以下步骤:
-
通过为您的功能编写测试来开始执行 TDD。
-
编写缺少的实现。
-
在本地克隆 Fraud Detection 服务存储库。
-
在欺诈检测服务的存储库中本地定义合同。
-
添加 Spring Cloud Contract (SCC) 插件。
-
运行集成测试。
-
提交拉取请求。
-
创建初始实施。
-
接管拉取请求。
-
编写缺少的实现。
-
部署您的应用程序。
-
在线工作。
我们从贷款发放流程开始,下面的 UML 图显示了该流程:
通过为您的功能编写测试来开始执行 TDD
下面的清单显示了一个测试,我们可能使用它来检查贷款金额是否太过 大:
假设您已经编写了新功能的测试。如果贷款申请为大 收到金额后,系统应拒绝该贷款申请,并提供一些说明。
编写缺失的实现
在某个时间点,您需要向 Fraud Detection 服务发送请求。假设
您需要发送包含客户端 ID 和金额的请求
客户想借钱。您希望使用 该方法将其发送到 URL。
为此,您可以使用类似于以下内容的代码:/fraudcheck
PUT
为简单起见,Fraud Detection 服务的端口设置为 ,并且
application 在 上运行。8080
8090
如果此时启动测试,它将中断,因为当前没有服务在端口 上运行。8080 |
在本地克隆 Fraud Detection 服务存储库
你可以从玩弄服务器端合约开始。为此,您必须首先 通过运行以下命令克隆它:
$ git clone https://your-git-server.com/server-side.git local-http-server-repo
在 Fraud Detection Service 的存储库中本地定义合同
作为消费者,您需要定义您到底想要实现的目标。您需要制定 您的期望。为此,请编写以下 contract:
将合同放在文件夹中。文件夹
很重要,因为生成者的测试基类名称引用该文件夹。src/test/resources/contracts/fraud fraud |
以下示例显示了我们在 Groovy 和 YAML 中的合约:
YML 合约非常简单。但是,当您查看合同时
使用静态类型的 Groovy DSL 编写,您可能想知道这些部分是什么。通过使用此表示法,Spring Cloud
Contract 允许您定义 JSON 块、URL 或其他动态结构的各个部分。在这种情况下
的标识符或时间戳,则无需对值进行硬编码。您希望允许一些
不同的值范围。要启用值范围,您可以设置正则表达式
与使用者端的这些值匹配。您可以通过以下方式提供正文
映射表示法或带有插值的 String。我们强烈建议使用 map 表示法。value(client(…), server(…))
要设置合约,您必须了解 map 表示法。请参阅有关 JSON 的 Groovy 文档。 |
前面显示的合同是双方之间的协议,该协议:
-
如果发送的 HTTP 请求包含所有:
-
端点上的方法
PUT
/fraudcheck
-
一个 JSON 正文,其中 a 与正则表达式匹配且等于
client.id
[0-9]{10}
loanAmount
99999
-
值为
Content-Type
application/vnd.fraud.v1+json
-
-
然后,将 HTTP 响应发送给使用者,该响应
-
具有状态
200
-
包含一个 JSON 正文,其字段包含值 和 值为
fraudCheckStatus
FRAUD
rejectionReason
Amount too high
-
具有值为
Content-Type
application/vnd.fraud.v1+json
-
准备好在集成测试中实际检查 API 后,您需要 在本地安装存根。
添加 Spring Cloud Contract Verifier 插件
我们可以添加 Maven 或 Gradle 插件。在此示例中,我们将展示如何添加 Maven。
首先,我们添加 BOM,如下例所示:Spring Cloud Contract
接下来,添加 Maven 插件,如下例所示:Spring Cloud Contract Verifier
由于添加了插件,您可以获得功能,其中包括
从提供的 Contract 中:Spring Cloud Contract Verifier
-
生成并运行测试
-
生成并安装存根
您不想生成测试,因为您作为使用者只想使用 存根。您需要跳过测试生成和调用。为此,请运行以下命令:
$ 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 Contract Stub Runner 的自动
stub 下载,则必须在 Consumer 端项目 () 中执行以下操作:Loan
Application service
-
添加 BOM,如下所示:
Spring Cloud Contract
-
将依赖项添加到 中,如下所示:
Spring Cloud Contract Stub Runner
-
使用 .在注释中,提供 和 以便 Stub Runner 下载 合作。
@AutoConfigureStubRunner
group-id
artifact-id
-
(可选)由于您正在离线与协作者一起玩游戏,因此您 也可以提供离线工作开关 ()。
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 已找到您的存根并为您的应用程序启动了一个服务器
组 ID 为,工件 ID 为 版本
存根和端口上的分类器。com.example
http-server
0.0.1-SNAPSHOT
stubs
8080
生产者端(欺诈检测服务器)
作为 Fraud Detection 服务器(贷款发放服务的服务器)的开发人员,您 可能想要:
-
接管拉取请求
-
编写缺失的实现
-
部署应用程序
以下 UML 图显示了欺诈检测流程:
接管 Pull Request
提醒一下,下面的清单显示了初始实现:
然后,您可以运行以下命令:
$ git checkout -b contract-change-pr master
$ git pull https://your-git-server.com/server-side-fork.git contract-change-pr
您必须添加自动生成的测试所需的依赖项,如下所示:
在 Maven 插件的配置中,必须传递该属性,如下所示:packageWithBaseClasses
此示例通过设置属性来使用 “基于约定” 的命名。这样做意味着最后两个包合并为
make 基测试类的名称。在我们的例子中,合同被放在 下。由于您没有两个从
文件夹,只选择一个,它应该是 .添加后缀和
利用。这将为您提供测试类名称。packageWithBaseClasses src/test/resources/contracts/fraud contracts fraud Base fraud FraudBase |
所有生成的测试都扩展了该类。在那里,你可以设置你的 Spring Context
或任何必要的。在这种情况下,您应该使用 Rest Assured MVC 来
启动 SERVER 端 。下面的清单显示了该类:FraudDetectionController
FraudBase
现在,如果运行 ,将获得类似于以下输出的结果:./mvnw clean install
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,你可以看到 Contract 的所有部分都被注入到测试中。
如果您使用 YAML,则这同样适用于 .producer()
value(consumer(…), producer(…))
matchers
response
请注意,在生产者端,您也在执行 TDD。期望被表达出来
以测试的形式。此测试向我们自己的应用程序发送一个请求,其中包含 URL
headers 和 body 中定义的 Body。它还需要精确定义的值
在响应中。换句话说,您有 、 和 的部分。是时候将 转换为 了。red
red
green
refactor
red
green
消费者方(贷款发放),最后一步
作为贷款发放服务的开发人员(Fraud Detection 服务器的使用者),您需要:
-
将我们的功能分支合并到
master
-
切换到在线工作模式
下面的 UML 图显示了进程的最终状态:
将分支合并到 Master
以下命令显示了使用 Git 将分支合并到 master 的一种方法:
$ git checkout master
$ git merge --no-ff contract-change-pr