关键词:
- Spring Cloud Contract:一个CDC Testing框架,类似的还有Pact
- CDC:
Consumer Driven Contract
Testing - Provider:
服务提供方
- Consumer:
服务调用方
什么是契约测试
微服务系统由大量的微服务节点组成,对其中一个服务节点做测试,需要部署依赖的服务节点,实际应用中会有以下的问题:
- 依赖服务没有开发完成,无法部署,导致无法测试。
- 依赖服务不稳定(测试环境问题、部署异常、数据问题等等),导致测试不通过。
- 依赖的服务发生变化没有知会到调用服务的一方,导致测试不通过。
在这次测试中,我们定义调用服务或者说消费服务的一方为Consumer,而依赖的服务提供方为Provider
针对以上问题,CDC主要定义了以下特性:
- Consumer根据自己的对Provider的期望编写Contract
- Provider根据Contract实现接口并进行测试(CDC框架可以根据Contract自动生成测试代码用于验证Provider提供的服务是否和Contract一致)
- Provider根据Contract生成Stubs实现对Provider进行Mock。
Sping Cloud Contract代码实例
一、通过契约验证Provider的服务和Contract是否一致
Provider引入依赖
引入依赖到/src/test目录所在模块的pom.xml中
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<version>2.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
实际如下图
引入plugin到/src/test目录所在模块的pom.xml中
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>2.2.4.RELEASE</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>com.alibaba.cxdc.qxc.sweetnurse.BaseMock</baseClassForTests>
</configuration>
</plugin>
如下图:
Provider端编写契约
契约可以使用groovy(推荐)或者YAML编写,我的契约文件存放路径为src/test/resources/contracts
契约对应的provider接口为:
Provider端根据Contract自动生成Test Class
执行命令:mvn clean install
生成的stubs.jar会自动安装到本地Maven仓库(
.m2/repository
):执行生成的Test验证Provider提供的服务和Contract定义是否一致
执行命令:mvn clean install
或者mvn test
时,会根据契约验证provider提供的服务是否和契约描述的一致:
1.契约描述返回值为xxx,实际接口返回为ceshi,所以test执行不通过:
2.修改契约文件如下:
3.验证通过:
后续如果Provider接口发生了变化,测试会验证不通过。
二、Consumer基于stubs进行mock测试
安装stubs.jar到本地Maven仓库
Provider的目录下执行命令mvn clean install
会自动安装stub包到本地Maven仓库
本文中stubs.jar的Maven坐标如下:
- groupId:
com.alibaba.cxdc.qxc
- artifactId:
sweetnurse-start
- version:
1.0.0
- classfier:
stubs
Consumer端引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
编写Consumer的测试类
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL,
ids = "com.alibaba.cxdc.qxc:sweetnurse-start:1.0.0:stubs:10001")
public class StubTest {
private String url = "http://localhost:10001";
@Test
public void testMethod() throws Exception {
RestTemplate restTemplate = new RestTemplate();
JSONObject param = new JSONObject();
param.put("contract", "ceshi");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<JSONObject> entity = new HttpEntity<>(param,requestHeaders);
ResponseEntity<String> result = restTemplate.postForEntity(url + "/rest/workshift/sayHello", entity,
String.class);
System.out.println(result.getStatusCode());
}
}
实际代码如图:
执行结果如图:
AutoConfigureStubRunner注解及内部属性的含义:
1.@AutoConfigureStubRunner
:根据ids属性获取stubs.jar并启动web服务器供测试mock调用
2.ids
的含义
ids = "com.alibaba.cxdc.qxc:sweetnurse-start:1.0.0:stubs:10001
ids = "groupId:artifactId:version:classfier:port"
其中version如果用+表示取最新版本
3.stubsMode
的含义:
StubRunnerProperties.StubsMode.LOCAL
:从本地的maven仓库获取stubs.jar
StubRunnerProperties.StubsMode.REMOTE
:从远程maven仓库获取stubs.jar
StubRunnerProperties.StubsMode.CLASSPATH
:默认值、从本地java classpath获取stubs.jar
参考文档:
Spring Cloud Contract Referenct
Pact
What's Next?
1.Pact框架和Spring Cloud Contract区别,针对不同语言的适用性是否更好。
2.怎么在现有自动化测试平台中实现或者集成契约测试能力。