使用Swagger实现消费驱动合同CDC

banq 18-07-19
                   

消费驱动合同(Consumer Driven Contracts:CDC)是一种软件工程方法,能让团队以TDD风格设计其分布式架构。Spring Cloud Contract Swagger支持Swagger API规范的合同测试。

当从单体架构迁移到微服务以后,复杂性转移就转移到了架构层面,团队需要定义他们的微服务如何相互通信,集成测试则需要大量时间进行测试设置,并且经常因为各种修改导致微服务发生错误行为进而无法响应正确。

消费驱动合同及其好处

消费驱动合同能够以TDD风格设计其分布式架构。Spring Cloud Contract提供合同测试功能。假设我们有一个生产者微服务,它为消费者微服务提供REST端点,在Spring Cloud Contract中,消费者开发团队能以合同的形式定义预期请求以及对生产者微服务的预期调用响应;生产者开发团队则在测试中针对其端点运行这些合同,如果能成功完成测试,它将生成存根并将其发布到artefact存储库中,存根是一个json契约,用正则表达式匹配器定义端点的请求和响应。

通过在合同测试中使用存根运行器,使用者可以在任意端口上拉取并实例化这些“可信”存根来模拟生产者微服务,并实例化整个微服务以进行测试并验证生成的存根。

Swagger规范
Spring Cloud Contract已经在YAML、JSON和Groovy中提供了合同表示法,但是,有些公司使用像Swagger这样的流行格式来指定他们的API,这样维护API规范和CDC会避免各种开销,因此,我们可以创建Spring Cloud Contract Swagger转换器,因而可以将Swagger规范用作我们的合同。

在这个案例中,我们使用Swagger定义消费者和生产者之间的API通信,Spring Cloud Contract Swagger项目将我们的API规范转换为Spring Contract格式,Spring Cloud Contract则会完成剩下的工作,并测试我们的模拟微服务以及任何其他合同格式。我们可以使用生成器生成的存根来测试消费者的传出API调用。

本节案例GitHub链接

https://github.com/SvenBayer/spring-cloud-contract-swagger-sample

Maven依赖

<groupId>blog.svenbayer</groupId>
<artifactId>spring-cloud-contract-swagger</artifact>


生产者

首先,我们需要配置生产者的pom.xml,需要在属性部分中定义Spring版本,我们使用版本2.0.0.RELEASE for Spring Cloud Contract,但是,Swagger文件扩展名不能以yml或yaml结尾!否则,Spring Cloud Contract将使用YamlConverter而不是SwaggerContractConverter解析它们。如果要使用yml扩展名,可以使用当前最新的SNAPSHOT版本,并在pom.xml的属性部分中定义它们。

<spring-cloud.version>Finchley.BUILD-SNAPSHOT</spring-cloud.version>
<spring-cloud-contract.version>2.0.1.BUILD-SNAPSHOT</spring-cloud-contract.version>
<spring-cloud-contract-swagger.version>1.0.1.RELEASE</spring-cloud-contract-swagger.version>


接下来,我们必须定义远程存储库和依赖关系:

首先需要将Spring Cloud Contract Verify添加到pom.xml,这样我们可以使用REST验证,我们的测试是在没有servlet容器的情况下运行,因此执行得更快。

下一步要将我们的Swagger文件转换为合同并让Producer生产者执行它,需要将spring-cloud-contract-maven-plugin 作为插件添加到pom.xml,将spring-cloud-contract-swagger作为插件依赖项添加。

使用MockitoJUnitRunner来作为测试基础并使用REST Assured来模拟测试控制器。

使用mvn verify执行测试时 , Spring Cloud Contract将生成一个合同测试,该测试继承我们的基类并包含合同中的数据,它还将生成json格式的存根。使用mvn install或mvn deploy,就会将这些存根和Swagger文件发布到消费者的存根罐中。

消费者
与生产者类似,我们需要配置属性,远程存储库和依赖关系管理。

我们将spring-cloud-starter-contract-stub-runner和转换器spring-cloud-contract-swagger添加为依赖项 。

我们需要编写针对消费者端点执行的测试,并使用MockMVC模拟生产者。我们的消费者将在模拟servlet环境中启动。在@AutoConfigureStubRunner中,我们指定存根模式,例如LOCAL和存根以及Swagger文件复制。通过 @StubRunnerPort,我们可以注入正在运行的存根的端口,并配置我们的消费者在该端口运行。

推荐的设置
以下设置能让消费者和生产者两个团队同时工作。消费者团队不需要等待生产者团队的基类和API实现。

Git
我们最好在单独的Git存储库中定义Swagger规范,消费者和生产者的两个团队都应该有权访问此存储库。

本文Spring Cloud Contract案例的Git存储库中,执行mvn verify时,会生成存根并将其移动到合同旁边的mappings文件夹中。您可以定义一个Jenkins作业DSL来执行mvn验证,并在每次提交时将存根推送到Git。

案例中生产者是swagger-coffee-producer-git,而消费者是 swagger-coffee-consumer / MissionLaunchControllerGitTest。

Maven 配置
使用Maven进行设置可以更好地控制Maven和Spring Cloud Contract的版本控制。在 swagger-coffee-contract中,我们将Swagger规范存储在自定义文件夹结构中。我们可以生成存根并将它们部署到我们的专门存储库。

生产者 swagger-coffee-producer-external在spring-cloud-contract-maven-plugin配置中将swagger-coffee-contract的输出生成定义为合同依赖 。

消费者 swagger-coffee-consumer / MissionLaunchControllerExternalTest定义 - 与任何其他消费者一样 - 将外部合同定义为在其测试中运行的存根。

Swagger值的配置
目前,Spring Cloud Contract Swagger为Swagger文档的字段生成默认值。


Boolean: true
Number: 1
Float/Double: 1.1
String: (the name of the String)

要设置自己的默认值,可以使用参数和响应部分中的 x-example字段,在definitions 部分中,还可以使用 x-example 或支持的example字段。应该避免使用 default 字段,因为当前的Swagger解析器(1.0.36)将default 字段的数值解释为String。

关于顺序,转换器将首先评估 example,然后是x-example,然后是default域。如果它没有找到预定义的值,它将向下一直到原始字段。转换器将仅使用Swagger方法项的第一次响应。

资源:
Spring Cloud Contract示例Git存储库
Spring Cloud Contract Swagger示例
Spring Cloud Contract Swagger

原文:
Consumer Driven Contracts with Swagger – Sven Baye

参考:
使用Jenkins、Artifactory和Spring Cloud Contract持续集成测试REST/JSON