消费者驱动契约(Consumer-Driven Contracts,CDC)测试,是指从消费者业务实现的角度出发,驱动出契约,再基于契约,对提供者验证的一种测试方式。
Spring Cloud Contract是一个实现了消费者驱动契约(CDC,Consumer-Driver Contracts)的端到端的服务测试框架。
为什么需要Spring Cloud Contract
通常我们要测试一个端到端的服务有两种方式
-
部署所有的服务进行端到端的测试
-
优点:
- 模拟生产环境
- 可以测试两个服务之间真实的通信情况
-
缺点:
- 为了测试一个服务,需要部署启动其他服务
- 需要花费长时间部署运行服务
- 测试中的反馈非常缓慢
- 调式非常困难
-
-
在单元测试或者集成测试中mock其他服务进行测试
-
优点:
- 快速的结果反馈
- 对基础设置没有要求
-
缺点:
- 为服务提供方创建的stub可能与真实的服务无关
- 测试成功生产环境可能失败
-
Spring Cloud Contract 解决了以上缺点,通过创建服务提供方的stub,获取快速响应的同时也能模拟真实的服务之间通信的情况。
如何使用Spring Cloud Contract
-
定义契约
在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 -
producer实现
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-verifier</artifactId> <scope>test</scope> </dependency> -
引入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文件中
如果指定了基类,则与基类在同一目录下,且生成的单元测试类会继承基类
-
-
按照契约编写代码实现
@RestController public class UserController { @GetMapping("/getUser") public User getUser() { return new User(1, "user"); } } -
执行mvn clean install 生成stub.jar
-
-
consumer实现
-
引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> <version>3.1.9</version> </dependency> -
配置stubrunner
consumer要使用producer提供的stub进行测试,需要指定stub的获取方式。
id的格式为:[groupId]:artifactId:[version]:[classify]:[port]
stubMode表示获取stub的方式:local|remote|classpath
stubrunner支持在配置文件中或者注解中设置
-
在application.yml中声明
stubrunner: ids: com.example:SpringContractProviderDemo:+:10101 classifier: stubs stubs-mode: local # +号表示获取最新的版本。local表示从默认的本地maven仓库(./m2目录)下寻找 -
使用@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 {
-
-