契约测试之 - 使用Pact-JS编写契约测试

news2024/11/16 18:03:14

   契约测试是一种通过对每个应用程序进行孤立检查,以确保其发送或接收的消息符合在“合同”中记录的共享理解的集成点测试技术。对于通过HTTP进行通信的应用程序,这些“消息”将是HTTP请求和响应,而对于使用队列的应用程序,则是放入队列中的消息。在实践中,实施契约测试的常见方式是:检查所有对测试替身的调用是否返回与对真实应用程序的调用相同的结果。
  契约测试尝用于微服务中,当一个系统由多个微服务组成时,服务于服务中间通过接口或者消息进行交互,服务间的沟通就变得至关重要,即provider端的任何修改都要能及时通知到consumer端,这样才不会导致consumer端的失败。契约测试就是有效解决provider端和consumer端沟通的一种测试手段,保证provider端提供的服务于consumer端使用的服务是一致的,不用等到服务集成测试时,才发现不一致。

  实施契约测试的工具主要有两个,Pact和SCC(Spring-cloud-contract),SCC需要与Spring的框架配合使用,所以,相对来说,Pact的使用面积更广,Pact提供了Pact-JVM,Pact-JS,Pact-Go,Pact-Python等客户端,可以支持不同编程语言技术栈应用。

  下面通过实际代码例子来看看如何编写契约测试,例子中使用Pact-JS,该例子来源于Pact官网。官网的例子中编写了多个demo code,以e2e中的例子为例,e2e下定义了provider服务,如下图中间的截图所示,provider里面定义了一些接口,且provider服务监听在8081端口,其次,是consumer端服务,consumer端的代码实现了调用provider端服务的逻辑,如下图右边截图,consumer端服务监听在8080端口。真正的契约测试编写在test目录下两个文件中,consumer.spec.js和provider.spec.js.

首先来看一下consumer.spec.js文件,测试代码中首先通过new Pact定义了基本信息,consumer,provider名词,后续生成的json格式的Contract文件名称就是consumer和provider的名称组合起来的;接着是port端口,运行consumer端测试时,实际Pact的作用是:根据契约信息启动了一个Mock服务,consumer端此时会调用Mock服务,而不是真实的provider端服务,至于如何用mock服务替换provider端服务稍后介绍,这里的port,定义的就是启动的mock服务端口,后面还有dir定义,即生成的契约文件的folder名称,spec:2,表示总共有2个契约测试Case。

  接着看看如果编写契约测试,编写契约测试主要包含两部分,第一部分就是通过Pact提供的matching规则编写接口的Request和Response,对于Get类请求,主要是编写Response,以下图为例,这里使用Like关键字定义了animalBodyExpectation,like表示,生成契约文件中对这个字段只做类型检查,契约测试重点关注的是接口的schema,即接口包含的字段以及字段的类型,不会去关注字段具体的值,因为接口字段值是属于服务端接口测试的范畴。第二部分就是编写consumer端的单元测试了,如右下图所示:在before阶段,通过调用provider.addInteraction({...})方法来定义启动起来的mock服务中,mock的接口的情况,这里state和uponReceiving都是接口的描述信息,withRequest和willResponse定义mock的接口的请求和响应。it(....)部分就是基于consumer端的代码编写单元测试,这里编写了调用consumer端的suggestion()方法,期望返回的结果。

当运行测试,将生成的契约上传到pact broker时,可以看到如下信息,第一个描述信息"A request for all animals given has some animals"就是上图before中定义的provider.addInteraction部分内容,在pact broker上点击超链接,可以跳转查看到pact启动的mock服务中,mock的接口信息的request和response。可以看到Response中每个字段的值和animalBodyExpectation中一致。

  前面提到过,在consumer端编写自己的代码时,调用的provider端接口,指定的肯定是provider端服务的baseUrl,那么,在运行consumer端测试时,如何用启动mock服务替换掉真实的provider端服务的呢?在顶层的describe()中,还有一段before()代码,这里调用provider.setup.then()的方法,里面做的事情,就是overwrite了环境变量API_HOST。

继续查看Consumer服务中的代码,发现consumer在调用第三方服务时,也定义了API_HOST这样一个环境变量来指定三方服务的baseUrl。

 总结下来,如果要编写契约测试,那么,consumer端,需要将调用的第三方服务的baseUrl抽取到环境变量中,这样在编写契约测试时,只需要overwrite环境变量,即可达到用mock服务替代真实第三方服务的目的。

  除了服务替换外,在编写契约测试时,还需要熟练掌握工具提供的Matching规则,因为,使用Pact编写契约测试,对于Provider端来说,会启动真实的服务,校验契约中的接口与真实Provider端的接口是否相同,使用matching时,以校验Type为主,基本不会涉及校验具体的值,因为,对于consumer来说,provider可能是其他团队在负责,他无法提前准备测试数据,所以,契约测试重点是校验schema。那么Pact-JS提供了哪些Matching规则呢?具体如下所示。在校验类型时,可以用like关键字,或者直接写类型,如string,number,boolean,integer等,对于数组类型的信息,可以用eachLike关键字。更多详细信息可看官网。

    上面review了consumer端的测试,再来看看provider端的测试,provider端的测试相对比较固定,需要注意一点,new Verifier({...})中provider名称要和consumer中定义的名称一致。另外,是配置pact broker的信息,例如登录的用户名称、密码等,下面配置的是一个public的pact borker信息。

   上面从代码层面介绍了如何通过Pact-JS编写契约测试,接着看看如何运行测试,具体步骤如下所示:

1.从官网下载代码
2.安装pact-foundation (npm i -S @pact-foundation/pact@latest)
3.cd到example目录下的e2e目录,安装依赖(npm install)
4.npm run test:consumer (from e2e directory) - Run consumer tests
5.npm run test:publish (from e2e directory) - Publish contracts to the broker
6.npm run test:provider (from e2e directory) - Run provider tests

运行完成后,可以从日志中看到执行结果,结果如下所示:

  登录到pact-broker,可以查看pact详细信息,也可以查看provider端与consumer端的network- graph.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/805921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码版本管理工具 git

1. 去B站看视频学习,只看前39集: 01-Git概述(Git历史)_哔哩哔哩_bilibili 2.学习Linux系统文本编辑器的使用 vi编辑器操作指令分享 (baidu.com) (13条消息) nano编辑器的使用_SudekiMing的博客-CSDN博客 windows下载安装Git官…

《入门级-Cocos2d 4.0塔防游戏开发》---第三课:欢迎界面开发(一)

目录 一、开发环境介绍 二、开发内容 三、显示效果 四、知识点总结 4.1 场景转场 4.2 场景转场流程 4.3 MenuItemSprite和Sprite区别 一、开发环境介绍 操作系统:UOS1060专业版本。 cocos2dx:版本 环境搭建教程: 统信UOS下配置安装cocos2dx开…

Packet Tracer – 配置系统日志和 NTP

Packet Tracer – 配置系统日志和 NTP 目标 第 1 部分:配置系统日志服务 第 2 部分:生成日志记录事件 第 3 部分:手动设置交换机时钟 第 4 部分:配置 NTP 服务 第 5 部分:验证带时间戳的日志 拓扑图 场景 在本…

js的变量

目录 变量 var和let 1.for循环中的声明 2.暂时性死区 3.全局声明 4.条件声明 const声明 变量 java是一种强数据类型语言,对数据类型要求高,要声明清楚变量的类型 数据类型 变量名 值 -----> int a 10 而javaScrit是一种弱类型语言,在声明变…

mac cli文件管理器

背景 最近研究了一下在控制台查看文件的插件ranger, 官方的解释是:一个cli下的文件管理器。觉得效果也很酷炫,所以在此展示一下。 安装 brew install ranger配置生成 建议第一次使用的时候使用 ranger --copy-configall将会在~/.config/ranger目录输…

如何做好IT类的技术面试

目录 一、IT行业的招聘渠道 二、如何做好技术面试官 三、谈谈IT行业如何做好招聘工作 四、面试IT公司的小技巧 五、面试有哪些常见的问题 六、关于面试的一些建议 面试可能是我们每个人都必须会遇到的事情,而技术面试更具有专业性,以下会从几个方面…

实现一个简单的前端MVVM框架类似VUE

在本篇博客中,我们将使用原生JavaScript实现一个简单的前端MVVM框架,类似于VUE。MVVM是Model-View-ViewModel的缩写,是一种用于构建现代化、可维护的前端应用程序的架构模式。MVVM框架通过数据绑定和组件化的方式实现了视图与数据的双向绑定&…

【Docker】使用docker-maven-plugin插件构建发布推镜像到私有仓库

文章目录 1. 用docker-maven-plugin插件推送项目到私服docker1.1. 构建镜像 v1.01.2. 构建镜像 v2.01.3. 推送到镜像仓库 2. 拉取私服docker镜像运行3. 参考资料 本文描述了在Spring Boot项目中通过docker-maven-plugin插件把项目推送到私有docker仓库中,随后拉取仓…

读发布!设计与部署稳定的分布式系统(第2版)笔记25_互联层之路由和服务

1. 控制请求数量 1.1. 这个世界可以随时摧毁我们的系统 1.1.1. 要么拒绝工作 1.1.2. 要么扩展容量 1.1.3. 没有人会在与世隔绝的环境中使用服务,现在的服务大多必须处理互联网规模的负载 1.2. 系统的每次失效,都源自某个等待队列 1.3. 每个请求都会…

【雕爷学编程】Arduino动手做(97)---10段LED光柱模块2

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…

C#,数值计算——逻辑斯谛分布(logistic distribution)的计算方法与源程序

逻辑斯谛分布即增长分布,增长分布的分布函数是“增长函数”,亦称“逻辑斯谛函数”(logistic function),故增长分布亦称做“逻辑斯谛分布”。逻辑斯谛分布(logistic distribution)是一种连续型的概率分布,记为L(μ,γ),…

#systemverilog# 说说Systemverilog中《automatic》那些事儿

前面我们学习了有关systemverilog语言中有关《static》的一些知识,同static 关系比较好的哥们,那就是 《automatic》。今天,我们了解认识一下。 在systemveriog中,存在三种并发执行语句,分别是fork..join,fork...join_any和fork..join_none,其中只有fork...join_none不…

OSPF路由协议(红茶三杯CCNA)

链路状态路由协议 OSPF(开放式最短路径优先)Open Shortest Path First 是一种链路状态路由协议,无路由循环(全局拓扑),RFC2328 “开放”意味着非私有的 管理型距离:110 OSPF采用SPF算法计算到达…

vmware虚拟机屏幕太小怎么办

虚拟机里面安装Ubuntu有时候屏幕会自动调整,有时会不会自动调整。 当遇到屏幕太小怎么办? 调整Ubuntu屏幕分辨率就可以了。 我不能说不能通过设置虚拟机达到同样的效果, 但是我可以告诉你设置Ubuntu系统的分辨率可以解决这个问题。 具体…

python爬虫(一)_爬虫原理和数据抓取

关于Python爬虫,我们需要学习的有: Python基础语法学习(基础知识)HTML页面的内容抓取(数据抓取)HTML页面的数据提取(数据清洗)Scrapy框架以及scrapy-redis分布式策略(第三方框架)爬虫(Spider)、反爬虫(Anti-Spider)、反反爬虫(Anti-Anti-Spider)之间的斗…

VIS for AI :ConvNetJS

1.简单介绍: ConvNetJS是由斯坦福大学计算机科学系的Andrej Karpathy开发的一个深度学习框架,用于在浏览器中运行卷积神经网络(ConvNet)。ConvNetJS可以帮助开发人员在客户端(浏览器)上进行深度学习任务&a…

NLP From Scratch: 生成名称与字符级RNN

NLP From Scratch: 生成名称与字符级RNN 这是我们关于“NLP From Scratch”的三个教程中的第二个。 在<cite>第一个教程< / intermediate / char_rnn_classification_tutorial ></cite> 中&#xff0c;我们使用了 RNN 将名称分类为来源语言。 这次&#xff…

算法竞赛入门【码蹄集新手村600题】(MT1060-1080)

算法竞赛入门【码蹄集新手村600题】(MT1060-1080&#xff09; 目录MT1061 圆锥体的体积MT1062 圆锥体表面积MT1063 立方体的体积MT1064 立方体的表面积MT1065 长方体的表面积MT1066 射线MT1067 线段MT1068 直线切平面MT1069 圆切平面MT1070 随机数的游戏MT1071 计算表达式的值M…

[vue] 新项目配置整理(没写完,回头有空继续)

省流版(vue2项目)&#xff1a; 脚手架&#xff1a;vue create xxxx vuex&#xff1a;npm i vuex3 router : npm install vue-router3 vue cli创建项目 vue create xxxx(项目名称) 添加基本配置 module.exports {lintOnSave: false, // 关闭eslint检查publicPath:./, //…

Python(四十七)列表对象的创建

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…