契约测试和CDC Testing框架:Spring Cloud Contract

关键词:

  • 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执行不通过:


测试不通过,provider提供的服务和契约描述不一致

2.修改契约文件如下:


3.验证通过:


测试通过,provider提供的服务和契约描述一致

后续如果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());
    }
}

实际代码如图:



执行结果如图:


Consumer test执行通过

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.怎么在现有自动化测试平台中实现或者集成契约测试能力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 什么是契约测试 测试是软件流程中非常重要,不可或缺的一个环节。一般的测试分为单元测试,集成测试,端到端的手工测试,...
    RaiseHead阅读 4,095评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • Spring Cloud Contract是契约测试的一个实现,最早看到契约测试还是在《微服务设计》书中,不过那时...
    MrTT阅读 3,557评论 3 2
  • 什么是契约 如果从契约产生的阶段来说,现有资料表明最早要追溯到西周时期的《周恭王三年裘卫典田契》,将契约文字刻写在...
    ThoughtWorks阅读 2,923评论 1 12
  • 渐变的面目拼图要我怎么拼? 我是疲乏了还是投降了? 不是不允许自己坠落, 我没有滴水不进的保护膜。 就是害怕变得面...
    闷热当乘凉阅读 4,233评论 0 13