Spring Cloud Contract 微服务契约测试框架

简介

使用场景

主要用于在微服务架构下做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);

    }
}

原文地址:https://www.cnblogs.com/freshchen/p/12229111.html

时间: 2024-09-29 16:55:56

Spring Cloud Contract 微服务契约测试框架的相关文章

[转帖]微服务框架Spring Cloud介绍 Part2: Spring Cloud与微服务

微服务框架Spring Cloud介绍 Part2: Spring Cloud与微服务 http://skaka.me/blog/2016/08/03/springcloud2/ AUG 3RD, 2016 10:09 PM | COMMENTS 之前介绍过微服务的概念与Finagle框架, 这个系列介绍Spring Cloud. Spring Cloud还是一个相对较新的框架, 今年(2016)才推出1.0的release版本. 虽然Spring Cloud时间最短, 但是相比我之前用过的Du

基于Spring Cloud的微服务落地

请点击此处输入图片描述 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud.它包括: Spring Cloud Config:配置管理工具,支持使用Git存储配置内容,可以实现应用配置的外部化存储,支持客户端配置信息刷新.加密/解密配置内容等. Spring Clo

Spring Cloud Alibaba | 微服务分布式事务之Seata

Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Greenwich.SR2 Spring CLoud Alibaba:2.1.0.RELEASE 1. 概述 在构建微服务的过程中,不管是使用什么框架.组件来构建,都绕不开一个问题,跨服务的业务操作如何保持数据一致性. 2. 什么是分布式事务? 首先,设想一个传统的单体应用,无论多少内部调用,最后终归是在同一

写给新手的Spring Cloud的微服务入门教程

1. 微服务简介 1.1 什么是微服务架构 微服务架构是系统架构上的一种设计风格 将大系统拆分成N个小型服务 这些小型服务都在各自的线程中运行 小服务间通过HTTP协议进行通信 有自己的数据存储.业务开发.自动化测试和独立部署机制 可以由不同语言编写 小结:微服务架构的思想,不只是停留在开发阶段,它贯穿了设计,研发,测试,发布,运维等各个软件生命周期. 2. 架构体系 架构样例: 2.1 微服务发布--持续集成 3. 微服务架构九大特性 服务组件化-- 组件是可独立更换.升级的单元.就像PC中的

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

Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Spring Cloud Netflix.Spring Cloud CloudFoundry.Spr

基于Spring Cloud的微服务构建学习-3 服务治理:Spring Cloud Eureka

基于Spring Cloud的微服务构建学习-3 服务治理:Spring Cloud Eureka 什么是服务治理 服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 为什么需要服务治理模块 在最初构建微服务系统的时候可能服务并不多,我们可以通过做一些静态配置来完成服务调用 此时看着一切都还正常. 随着项目逐渐接近尾声,维护人员需要维护的服务越来越多,越来越复杂,最终形成大量的配置文件,维护将会变得越来越困难.此时,微服务应用实例自动化管理框架变得

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

原文来源:http://blog.didispace.com/springcloud1/ Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Sprin

利用Spring Cloud实现微服务- 熔断机制

1. 熔断机制介绍 在介绍熔断机制之前,我们需要了解微服务的雪崩效应.在微服务架构中,微服务是完成一个单一的业务功能,这样做的好处是可以做到解耦,每个微服务可以独立演进.但是,一个应用可能会有多个微服务组成,微服务之间的数据交互通过远程过程调用完成.这就带来一个问题,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的"扇出".如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的&

Spring Cloud构建微服务架构服务注册与发现

Spring Cloud简介Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Spring Cloud Netflix.Spring Cloud0 CloudFoundry.S