文章目录

  • Spring-Cloud-Contract
    • 1. 多服务、多团队系统、前后端联调使用
    • 2. 契约工作流程
    • 3. 使用契约-Producer side(服务提供端)
      • 3.1 添加依赖&插件
      • 3.2 创建测试基类
      • 3.3 Producer side-待测试的接口
      • 3.4 Producer side-添加合同
      • 3.5 Maven install(Producer side生成stubs-jar)
    • 4.Consumer Side(消费存根)
      • 4.1 Consumer Side-添加依赖
      • 4.2 写测试类(消费存根)
    • 5.主要应用场景
      • 5.1 多服务、多团队,跨服务测试
      • 5.2 使用契约进行联调
        • 5.2.1 下载WireMock standalone(不推荐这种方式)
        • 5.2.2 .json放到__mapping下(不推荐)
        • 5.2.3 访问mock接口
      • 5.3 确保接口符合契约
    • 6.自动化

Spring-Cloud-Contract

消费者驱动的契约测试(Consumer-Driven Contracts,简称CDC),是指从消费者业务实现的角度出发,驱动出契约,再基于契约,对提供者验证的一种测试方式。

主要应用场景

1. 多服务、多团队系统、前后端联调使用

若想测试应用v1,我们可以:

  • 部署所有微服务并执行端到端测试。

优点:
模拟生产。
测试服务之间的真实通信。

缺点:
要测试一个微服务,我们必须部署6个微服务,几个数据库等。

运行时间很长,稳定性差,容易失败。

非常难以调试,依赖服务不受控制。

  • 在单元/集成测试中模拟其他微服务。

优点:
非常快速的反馈,简单易用。

没有基础设施要求,如DB,网络等。

缺点:

模拟不够真实。
部分场景测试不到。

2. 契约工作流程

使用契约后,测试v1就不用启动其他服务了(有依赖其他服务的数据的话)。

通俗来讲,契约使用步骤可大致分为:

2.1 生产者提供定义好的契约(接口,包含request Method、header,parameter,body)

2.2 生产者生成stub jar,提供给消费者,可mvn install到Maven库(本地/远程仓库)

2.3 消费者调用生产者的接口(从契约获取数据)


更为详细的契约工作流程如下:

Spring-Cloud-Contract的开发者MARCIN GRZEJSZCZAK在博客中提到:Spring Cloud Contract in a polyglot world

The producer:(生产者)

  • Applies a Maven or Gradle Spring Cloud Contract plugin.
  • (译) 使用Maven/Gradle的Spring Cloud Contract插件。
  • Defines YAML contracts under src/test/resources/contracts/.
  • (译) 在目录src/test/resources/contracts下,定义Groovy/YAML形式的合同。
  • Generates tests and stubs from the contract.
  • (译) 从契约中生成测试类和存根
  • Creates a base class that extends the generated tests and sets up the test context.
  • (译) 创建一个基类并设置测试的上下文,用于被生成的测试类继承
  • Once the tests pass, creates a JAR with stubs classifier where contracts and stubs are stored.
  • (译) 测试通过后,会创建一个stubs-jar,其中存储了契约和存根
  • Uploads the JAR with a stubs classifier to binary storage.
  • (译) 上传stubs-jar到Maven库

The consumer:(消费者)

  • Uses Stub Runner to fetch the stubs of the producer. Stub Runner starts in memory HTTP servers (by default, those are WireMock servers) fed with the stubs.
  • (译) 使用stub Runner获取生产者的存根。Stub Runner在内存中启动了HTTP服务器(默认情况下,那些是WireMock服务器)。
  • Runs tests against the stubs.
  • (译) 针对存根运行测试。

Consequently, using Spring Cloud Contract and Contract Testing gives you:
(译) 因此,使用契约和契约测试会带给你

  • stubs reliability: They were generated only after the tests have passed.
  • (译) 存根可靠性:测试通过才生成
  • stubs reusability: They can be downloaded and reused by multiple consumers.
  • (译) 存根可重用性:可被多个消费者下载,使用

3. 使用契约-Producer side(服务提供端)

3.1 添加依赖&插件

<!-- 自动生成单元测试代码 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-contract-verifier</artifactId><version>2.0.3.BUILD-SNAPSHOT</version><scope>test</scope></dependency><!--该插件自动生成测试类、stubs(存根)--><plugin><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-contract-maven-plugin</artifactId><version>2.0.2.BUILD-SNAPSHOT</version><extensions>true</extensions><configuration><!--测试基类--><baseClassForTests>com.xiaobai.producer.BaseMock</baseClassForTests></configuration></plugin>

3.2 创建测试基类

创建插件指定的测试基类

BaseMock.java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
//测试的application context会被关闭,同时缓存会清除
@DirtiesContext
@AutoConfigureMessageVerifier
public class BaseMock {@Autowiredprivate WebApplicationContext context;@Beforepublic void setUp() {//使用上下文构建RestAssuredMockMvc.webAppContextSetup(context);}
}

3.3 Producer side-待测试的接口

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("/{id}")public UserPO getOneUser(@PathVariable("id") Integer id){/**(接口开发完成的情况)接口的返回结果跟契约定义的结果需一致,否则生成的测试类,断言会不通过,也就无法生成stub jar了。这种情况应该是契约的正确使用方式,消费者定义契约,验证生产者的接口是否符合契约,符合才能构建成功。(接口业务代码未实现的情况)可以不需要接口,只写契约,Maven install时,只需mvn clean install -DskipTests,即可跳过verifier的测试,这种情况我是用来将生成的.json扔到mock服务器上。**/return userMapper.selectByPrimaryKey(id);}...
}

3.4 Producer side-添加合同

合同默认位置src/test/resources/contracts,
支持Groovy或yaml编写的合同定义语言(DSL)

shouldReturnOneUserSuccess.groovy:

import org.springframework.cloud.contract.spec.ContractContract.make {//ignored()description "should return one user success"request {method 'GET'urlPath('/user/1')}response {status 200body('''{"id": 1,"childName": "小白","parentName": "大白","phone": "18880000"
}''')headers {header('Content-Type', 'application/json;charset=UTF-8')}}
}

3.5 Maven install(Producer side生成stubs-jar)

(接口未写业务代码的情况) mvn clean install -DskipTests

(接口已实现业务代码的情况) 直接install,插件会自动生成测试类(1),合同(2),映射的json(3),存根jar(4)

生成的测试类ContractVerifierTest.java

合同(2)即是我们3.4步骤书写的契约文件

映射的json文件(3),该文件可放到Mock服务器执行,后面会提到。

存根jar(4)已安装到本地Maven仓库,可提供给其他服务调用,后面会调用到。

4.Consumer Side(消费存根)

消费存根jar可以用Fegin,RestTemplate…这里笔者使用RestTemplate.

这里提一下,Fegin消费存根需要在application.yml增加stubrunner属性,如下:

#Fegin消费存根需增加的配置,意思是哪个jar包对应哪个Fegin,这样就无需注册中心了。
stubrunner:ids-to-service-ids:需要消费的jar包artifactID1:Fegin对应的value属性值1需要消费的jar包artifactID2:Fegin对应的value属性值2

4.1 Consumer Side-添加依赖

<!-- 自动下载、运行stub-jar --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-contract-stub-runner</artifactId><version>2.0.2.RELEASE</version></dependency>

4.2 写测试类(消费存根)

ConsumerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConsumerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//初始化测试配置,测试controller需要
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
@AutoConfigureStubRunner(ids = {"com.xiaobai:producer:+:stubs:10001"},stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@Slf4j
public class ConsumerTest {@Autowiredprivate RestTemplate restTemplate;@Testpublic void testMethod() throws Exception {ResponseEntity<JSONObject> response = restTemplate.exchange("http://localhost:10001/user/1",HttpMethod.GET,null,JSONObject.class);log.info("测试数据:"+ response.getBody().toJSONString());}
}

@AutoConfigureStubRunner自动下载存根,
ids属性格式
groupId:artifactId:version:classifier:port

运行该测试类

当测试上下文启动,无需启动生产者的服务,在测试类调用生产者的接口不会404,因为Spring Cloud Contract Stub Runner将自动启动测试中的WireMock服务器并使用从服务器端生成的存根来提供返回数据。

5.主要应用场景

消费者驱动契约,生产者根据契约进行开发,spring-cloud-contract-verifier确保了生产者的接口一定符合契约,才能构建成功。契约需要双方共同遵守,任意一方修改了契约,可能会导致测试失败。 如消费者更新了契约(旧版->新版),而生产者未更新业务代码,那么生产者的构建就会导致失败。
So,基于契约开发才是spring-cloud-contract的正确打开方式。

5.1 多服务、多团队,跨服务测试

当涉及多个系统时,可以通过公共的库,下载stubs-jar即可进行本地跨服务测试。

5.2 使用契约进行联调

如接口提供方,调用方存在多个团队,初期可使用契约进行联调。
如,前端需要后端提供接口,当后端开发滞后时,可先定义契约的入参、回参,部署到Mock服务器,前端调用Mock的请求,返回定义好的数据,这样就不会阻塞前端工作。

WireMock服务器可以在自己的进程中运行,并通过Java API,JSON over HTTP或JSON文件进行配置。

WireMock没怎么研究,我只会一种方式:将生产者生成的.json文件(/target/stubs/MERA-INF/groupId/artifactID/version/mappings下),扔到WireMock的/mapping目录下

5.2.1 下载WireMock standalone(不推荐这种方式)

(推荐) tips:将所有的.json文件扔到mock服务器未免太麻烦,stub runner将.json打包成stubs-jar,然后直接运行该jar也可达到相同效果
参考官方文档https://cloud.spring.io/spring-cloud-contract/single/spring-cloud-contract.html#_stub_runner_server_fat_jar

以下方式略显麻烦,可参考上面的stub_runner_server_fat_jar

http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.20.0/wiremock-standalone-2.20.0.jar

运行在本地或者服务器上

java -jar wiremock-standalone-2.18.0.jar --port 10001


启动Mock服务器会在当前目录生成2个空文件夹:__files和mappings。__files是放上传/下载/录制文件用的,mappings存放.json.

Tips:添加修改mapping文件后,都需要重启服务才能生效

5.2.2 .json放到__mapping下(不推荐)


将该.json放到Mock服务器的_mapping下。重启Mock的jar。

5.2.3 访问mock接口


此功能好像很多工具都可以实现,如淘宝的rap接口管理工具…

5.3 确保接口符合契约

如果使用spring-cloud-contract-verifier生成测试类的话,接口的业务代码返回的数据一定符合契约时,才能构建成功。这里也可用于单元测试,验证自己的接口格式,好处是不用写单元测试代码(自动生成)。

6.自动化

我认为, 契约正确打开方式应该是:

  1. 消费者定义契约(.groovy 或.yaml),发布到公共契约库。
  2. 生产者拉取契约,放至/src/test/resources/contracts下,然后生产者实现接口业务(如业务未实现的情况下,可以直接写.json到WireMock服务器下,这样也可用于给消费者通过Rest调用),spring-cloud-contract-verifier会验证接口是否符合契约的预期返回值,符合则构建stubs-jar成功。
  3. 消费者通过Stubs Runner远程下载,运行生产者的stubs-jar,即可进行契约测试,消费对方的契约。
    未实现…-.-

    上图参考的链接
    https://piotrminkowski.wordpress.com/tag/spring-cloud-contract/
    可供参考:
    https://www.baeldung.com/spring-cloud-contract

如果对您有帮助,不妨点赞支持我,有错误、改善的地方请指出。
契约的国内资料暂时比较少 ,有些踩过的坑,动态属性,正则匹配等, 本文未提到(懒得更新啦),如有疑问可以提出,或许我能提供帮助 ?

Spring-Cloud-Contract实战相关推荐

  1. Marcin Grzejszczak访谈:Spring Cloud Contract

    Marcin Grzejszczak是Pivotal的一名软件工程师.目前,他在从事Spring Cloud Contract的开发,这是一个消费者驱动的.面向Java的契约框架.为了了解该框架的一些 ...

  2. Spring Cloud Contract 契约测试实践

    本文转载公众号:永辉云创技术 该号由我参与维护,欢迎大家关注支持!!! 分布式研发模型演进 众所周知, 分布式系统是由众多微服务构成,并按照功能模块划分后, 由不同的开发小组进行维护. 研发模型如下图 ...

  3. 消费者驱动的微服务契约测试套件:Spring Cloud Contract

    在微服务架构下,你的服务可能由不同的团队提供和维护,在这种情况下,接口的开发和维护可能会带来一些问题,比如服务端调整架构或接口调整而对消费者不透明,导致接口调用失败. 为解决这些问题,Ian Robi ...

  4. 消费者驱动的微服务契约测试套件Spring Cloud Contract

    在微服务架构下,你的服务可能由不同的团队提供和维护,在这种情况下,接口的开发和维护可能会带来一些问题,比如服务端调整架构或接口调整而对消费者不透明,导致接口调用失败. 为解决这些问题,Ian Robi ...

  5. 消费者驱动的契约测试 Spring Cloud Contract介绍

    消费者驱动的契约测试 Spring Cloud Contract介绍 什么是契约测试 测试是软件流程中非常重要,不可或缺的一个环节.一般的测试分为单元测试,集成测试,端到端的手工测试,这也是构成测试金 ...

  6. 赠书:深入理解 Spring Cloud 与实战

    无论是Dubbo,还是Spring Cloud,大家可能都不会感到陌生. 那什么是Dubbo Spring Cloud呢?使用Dubbo Spring Cloud可以实现什么目的?基于其实现的路由和负 ...

  7. Spring Cloud Contract实践

    1.Spring Cloud Contract简介 Spring Cloud Contract是一个总体项目,其中包含帮助用户成功实施消费者驱动合同方法的解决方案.目前,Spring Cloud Co ...

  8. Spring Cloud Gateway实战之三:动态路由

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<Spring Cloud Ga ...

  9. spring cloud contract的应用实现与概念理解-服务请求者一侧的落地-细节较多避免踩坑卡壳

    笔者的经验认为,微服务的出现,是为了应对传统SOA架构在多服务背景下的疲软,本质上是SOA的进一步衍生.是一种治理服务的手段.而微服务之所以能够解决传统SOA.单块大单体程序的问题,原因在于微服务自身 ...

  10. 契约测试之Spring Cloud Contract

    在微服务架构下,服务间会通过某种形式的消息传递或API调用进行耦合,这让服务的集成以及测试变成了非常具有挑战的一件事.早在微服务流行之前,就有人提出了消费者驱动契约(Consumer-driven c ...

最新文章

  1. linux 服务器FTP服务安装教程
  2. 《大数据算法》一1.2 大数据算法
  3. vmware-images
  4. 主席树有关的一些题目(持续更新)
  5. 倒数日电脑版_应用日报|iOS 或更名为 iPhoneOS,倒数日 Mac 版上线限时免费
  6. Java的笔记开源软件_安装 MapGuide Open Source 2.0(Java版本)笔记
  7. 学校oj显示在线用户数超过了序列号允许。您需要购买或升级您的序列号
  8. Nginx实现会话保持
  9. 香港和内地重疾险25种常见重疾定义对比全解析
  10. MP3Play项目实战 (1)
  11. WPF中的StackPanel、WrapPanel、DockPanel
  12. JS解构和 ... 运算符
  13. 在Linux(unix)中,以波浪线“~”开始的文件名
  14. 原来微信就能生成证件照,再也不傻傻地往照相馆跑了,办法很简单
  15. 关于二叉树重构的思索
  16. App can't be opened because it is from an unidentified developer
  17. Hybrid App 和 React Native 开发那点事
  18. matlab清除所有图形窗口,matlab图形操作基础
  19. STM32 Proteus仿真GP2Y101红外测距温度湿度DHT11内部RTC-0010
  20. ACM纪念日 (15 分)

热门文章

  1. 【Linux高效小trick】Linux下杀死僵尸进程,释放GPU内存,让代码全速运行~
  2. 在git中有一种方法可以将单个文件中的更改拆分为两个提交吗?
  3. 网络DHCP配置简单介绍
  4. LMS 自适应滤波算法原理和实现(不使用自带函数库)
  5. 2023-02-20干活小计:
  6. css设置字体大小会受分辨影响吗,CSS字体大小设置时的参考(转)
  7. 常见3DS Max格式概述
  8. 全卷积网络FCN的缺陷
  9. C语言 简单迷宫设计
  10. 常见的HTTTP状态码