简介

使用场景

主要用于在微服务架构下做CDC(消费者驱动契约)测试。下图展示了多个微服务的调用,如果我们更改了一个模块要如何进行测试呢?

  • 传统的两种测试思路

    • 模拟生产环境部署所有的微服务,然后进行测试

      • 优点

        • 测试结果可信度高
      • 缺点
        • 测试成本太大,装一整套环境耗时,耗力,耗机器
    • Mock其他微服务做端到端的测试
      • 优点

        • 不用装整套产品了,测的也方便快捷
      • 缺点
        • 需要写很多服务的Mock,要维护一大堆不同版本用途的simulate(模拟器),同样耗时耗力
  • Spring Cloud Contrct解决思路

    • 每个服务都生产可被验证的 Stub Runner,通过WireMock调用,服务双方签订契约,一方变化就更新自己的Stub,并且测对方的Stub。Stub其实只提供了数据,也就是契约,可以很轻量的模拟服务的请求返回。而Mock可在Stub的基础上增加验证

契约测试流程

  • 服务提供者

    • 编写契约,可以用Groovy DSL 脚本也可以用 YAML文件
    • 编写测试基类用于构建过程中插件自动生成测试用例
    • 生成的测试用例会自动运行,这时如果我么提供的服务不能满足契约中的规则就会失败
    • 提供者不断完善功能直到服务满足契约要求
    • 发布Jar包,同时将Stub后缀的jar一同发布
  • 服务消费者
    • 对需要依赖外部服务的接口编写测试用例
    • 通过注解指定需要依赖服务的Stub jar包
    • 验证外部服务没有问题

简单案例

服务提供者

模拟一个股票价格查询的服务

项目地址

springcloud-contract-provider-rest

项目结构

项目依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency> <build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>2.2.1.RELEASE</version>
<extensions>true</extensions>
<configuration>
<!--用于构建过程中插件自动生成测试用例的基类-->
<baseClassForTests>
com.example.springcloudcontractproviderrest.RestBaseCase
</baseClassForTests>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

编写契约

既然是消费者驱动契约,我么首先需要制定契约,这里为了方便假设查询贵州茅台的股价返回值是固定的999,也可以通过正则等方式去限制返回值

Contract.make {
description "query by id should return stock(id,price)" request {
method GET()
url value {
// 消费者使用时请求任何 /stock/price/数字 都会被转为 /stock/price/600519
consumer regex('/stock/price/\\d+')
producer "/stock/price/600519"
}
} response {
status OK()
headers {
contentType applicationJson()
}
// 提供给消费者的默认返回
body([
id : 600519,
price: 999
]) // 服务端在测试过程中,body需要满足的规则
bodyMatchers {
jsonPath '$.id', byRegex(number())
jsonPath '$.price', byRegex(number())
}
}
}

测试基类

主要是加载环境,然后由于不是真实环境模拟了数据库查询

@SpringBootTest
@RunWith(SpringRunner.class)
public class RestBaseCase { @Autowired
private StockController stockController; @MockBean
private StockRepository stockRepository; @Before
public void setup() {
init();
RestAssuredMockMvc.standaloneSetup(stockController);
} private void init() {
Mockito.when(stockRepository.getStockById(600519)).thenReturn(new StockDTO(600519, "贵州茅台", 999L, "SH"));
} }

实现服务并测试

实现我们的服务功能,具体代码逻辑可以在项目地址中查看,然后测试看是否符合契约

mvn clean test

可以在生成(target)目录中找到 generated-test-sources 这个目录,插件为我们自动生成并且运行的case就在其中

public class StockTest extends RestBaseCase {

	@Test
public void validate_shoudReturnStockIdAndPrice() throws Exception {
// given:
MockMvcRequestSpecification request = given(); // when:
ResponseOptions response = given().spec(request)
.get("/stock/price/600519"); // then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*"); // and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); // and:
assertThat(parsedJson.read("$.id", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
assertThat(parsedJson.read("$.price", String.class)).matches("-?(\\d*\\.\\d+|\\d+)");
} }

发布

如果一切顺利就可以deploy了

服务消费者

模拟查询个人资产的服务,需要远程调用股票价格查询服务,计算总资产

项目地址

springcloud-contract-consumer-rest

项目结构

验证服务

编写测试用例验证服务

@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureStubRunner(
ids = {"com.example:springcloud-contract-provider-rest:+:stubs:8880"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL
)
public class StockApiTest { @Autowired
private StockApi stockApi; @Test
public void testStockApi() throws IOException {
StockPriceDTO stockPrice = stockApi.getStockPrice(600519).execute().body();
BDDAssertions.then(stockPrice.getId()).isEqualTo(600519);
BDDAssertions.then(stockPrice.getPrice()).isEqualTo(999); }
}

Spring Cloud Contract 微服务契约测试的更多相关文章

  1. Spring Cloud构建微服务架构(一)服务注册与发现

    Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁 ...

  2. Spring Cloud构建微服务架构(五)服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: 我们使用Spring Cloud Netflix中的Eureka实现了服务 ...

  3. Spring Cloud构建微服务架构 - 服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实 ...

  4. 【微服务】使用spring cloud搭建微服务框架,整理学习资料

    写在前面 使用spring cloud搭建微服务框架,是我最近最主要的工作之一,一开始我使用bubbo加zookeeper制作了一个基于dubbo的微服务框架,然后被架构师否了,架构师曰:此物过时.随 ...

  5. 基于Spring Cloud的微服务入门教程

    (本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...

  6. 干货|基于 Spring Cloud 的微服务落地

    转自 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的 ...

  7. 基于Spring Cloud的微服务落地

    微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务 ...

  8. Spring Cloud与微服务构建:Spring Cloud简介

    Spring Cloud简介 微服务因该具备的功能 微服务可以拆分为"微"和"服务"二字."微"即小的意思,那到底多小才算"微&q ...

  9. Spring Cloud与微服务构建:微服务简介

    Spring Cloud与微服务构建:微服务简介 单体架构及其不足 1.单体架构简介 在软件设计中,经常提及和使用经典的3曾模型,即表示层.业务逻辑层和数据访问层. 表示层:用于直接和用户交互,也成为 ...

随机推荐

  1. C# 如何在项目引用x86 x64的非托管代码

    因为现在的项目使用的是 AnyCpu 在 x86 的设备使用的是x86,在x64使用的是x64,但是对于非托管代码,必须要在x64使用x64的dll,在x86使用x86的dll.在C++没有和C#一样 ...

  2. MV*模式

    MV*模式 MVC框架最早出现在Java领域,然后慢慢在前端开发中也被提到,后来又出现了MVP,以及现在最成熟的MVVM. MVC model 数据模型 view 视图 controller 控制器 ...

  3. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(13)之会员登录注册

    源码下载地址:http://www.yealuo.com/Sccnn/Detail?KeyValue=c891ffae-7441-4afb-9a75-c5fe000e3d1c 会员中心,是我们与用户交 ...

  4. H3C查看历史命令--用户以上

    [H3Cwang]display history-command   sys   sysname H3C   sysname H3Cwang   display history-command   q ...

  5. classpath*与classpath

    classpath*:的出现是为了从多个jar文件中加载相同的文件. classpath:只能加载找到的第一个文件.

  6. Java虚拟机-字节码执行引擎

    概述 Java虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,成为各种虚拟机执行引擎的统一外观(Facade).不同的虚拟机引擎会包含两种执行模式,解释执行和编译执行. 运行时帧栈结构 栈帧(Sta ...

  7. codeforces 1183H 动态规划

    codeforces 1183H 动态规划 传送门:https://codeforces.com/contest/1183/problem/H 题意: 给你一串长度为n的字符串,你需要寻找出他的最长的 ...

  8. $Noip2014/Luogu1351$ 联合权值 树形

    $Luogu$ $Description$ 给定一棵树,每两个距离为$2$的点之间可以产生"联合权值","联合权值"定义为这两个数的乘积.求最大的联合权值以及所 ...

  9. Python用PIL将PNG图像合成gif时如果背景为透明时图像出现重影的解决办法

    最近在用PIL合成PNG图像为GIF时,因为需要透明背景,所以就用putpixel的方法替换背景为透明,但是在合成GIF时,图像出现了重影,在网上查找了GIF的相关资料:GIF相关资料 其中有对GIF ...

  10. 「洛谷P1306」斐波那契公约数 解题报告

    P1306 斐波那契公约数 题目描述 对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很"简单"问题:第n项和第m项的最大公 ...