Spring Cloud Contract学习

119 阅读2分钟

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

Spring Cloud Contract是一个实现了消费者驱动契约(CDC,Consumer-Driver Contracts)的端到端的服务测试框架。

为什么需要Spring Cloud Contract

通常我们要测试一个端到端的服务有两种方式

  1. 部署所有的服务进行端到端的测试

    • 优点:

      1. 模拟生产环境
      2. 可以测试两个服务之间真实的通信情况
    • 缺点:

      1. 为了测试一个服务,需要部署启动其他服务
      2. 需要花费长时间部署运行服务
      3. 测试中的反馈非常缓慢
      4. 调式非常困难
  2. 在单元测试或者集成测试中mock其他服务进行测试

    • 优点:

      1. 快速的结果反馈
      2. 对基础设置没有要求
    • 缺点:

      1. 为服务提供方创建的stub可能与真实的服务无关
      2. 测试成功生产环境可能失败

Spring Cloud Contract 解决了以上缺点,通过创建服务提供方的stub,获取快速响应的同时也能模拟真实的服务之间通信的情况。

如何使用Spring Cloud Contract

  1. 定义契约

    在test/resources/contracts目录下创建契约,契约的格式可以是groovy或者yml

    name: getUser
    request:
      method: GET
      url: /getUser
      headers:
        Content-Type: application/json
    
    response:
      status: 200
      body:
        id: 1
        username: "user"
      headers:
        Content-Type: application/json
    
  2. producer实现

    1. 引入依赖

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-contract-verifier</artifactId>
          <scope>test</scope>
      </dependency>
      
    2. 引入spring-cloud-contract-maven-plugin插件并指定基类

      <plugin>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-contract-maven-plugin</artifactId>
          <version>3.1.9</version>
          <extensions>true</extensions>
          <configuration>
              <baseClassForTests>
                  com.example.springcontractproviderdemo.SpringContractProviderDemoApplicationTests
              </baseClassForTests>
          </configuration>
      </plugin>
      
      • 基类的作用是配置测试环境,如对需要调用的第三方服务进行mock等。并且Spring Cloud Contract会根据定义的契约自动生成单元测试代码并执行。

        在不指定基类时,默认的单元测试代码在 target/testclasses/org/springframework/cloud/contract/verifier/tests目录下的ContractVerifierTest.class文件中

        如果指定了基类,则与基类在同一目录下,且生成的单元测试类会继承基类

    3. 按照契约编写代码实现

      @RestController
      public class UserController {
      
          @GetMapping("/getUser")
          public User getUser() {
              return new User(1, "user");
          }
      }
      
    4. 执行mvn clean install 生成stub.jar

  3. consumer实现

    1. 引入依赖

      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
          <scope>test</scope>
          <version>3.1.9</version>
      </dependency>
      
    2. 配置stubrunner

      consumer要使用producer提供的stub进行测试,需要指定stub的获取方式。

      id的格式为:[groupId]:artifactId:[version]:[classify]:[port]

      stubMode表示获取stub的方式:local|remote|classpath

      stubrunner支持在配置文件中或者注解中设置

      1. 在application.yml中声明

        stubrunner:
          ids: com.example:SpringContractProviderDemo:+:10101
          classifier: stubs
          stubs-mode: local
          
        # +号表示获取最新的版本。local表示从默认的本地maven仓库(./m2目录)下寻找
        
        
      2. 使用@AutoConfigureStubRunner声明

        //如果stubMode为Remote,则还需要配置远程仓库地址repositoryRoot
        
        @ExtendWith(SpringExtension.class)
        @AutoConfigureStubRunner(ids = {"com.example:SpringContractProviderDemo:+:8080"}, stubsMode = StubRunnerProperties.StubsMode.REMOTE,repositoryRoot = "localhost:8081/nexus/stubs")
        @SpringBootTest(classes = SpringContractClientDemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
        class SpringContractClientDemoApplicationTests {