利器 | REST Assured 实践(二):断言实现

news2024/11/24 7:56:15


在上一篇文章中,我们初步探讨了 REST Assured 的应用实践,还有很多丰富的用法需要慢慢探索研究。而 REST Assured 提供的完整断言手段,是测试工程师最常用最重要的功能之一。断言该如何使用呢?

这里以 rest-assured 官方给的一个示例做演示学习

{
"lotto":{
 "lottoId":5,
 "winning-numbers":[2,45,34,23,7,5,3],
 "winners":[{
   "winnerId":23,
   "numbers":[2,45,34,23,3,5]
 },{
   "winnerId":54,
   "numbers":[52,3,12,11,18,22]
 }]
}
}

在本地使用 python -m CGIHTTPServer 临时搭建起一个服务:

根节点.子节点
1)我们可以使用根节点.(点)子节点的方式一层层的找下去,例如我们需要对lottoId等于 5 进行断言:

@Test
void testGPath(){
     given().
     when().
             log().all().get("http://127.0.0.1:8000/restAssured.json").
     then().
             log().all().body("lotto.lottoId",equalTo(5));
 }

2)如果我们想要断言winners数组下面的winnerId,检查23和54是否包含其中,可以如下lotto.winners.winnerId写法

@Test
void testGPath(){
    given().
    when().
            log().all().get("http://127.0.0.1:8000/restAssured.json").
    then().
            log().all()
            .body("lotto.winners.winnerId",hasItems(54,23));
}

索引取值

1)如果我们想要取某些相同字段中的某一个,可以使用类似索引的方式获取,例如想要断言 winners 数组下面的 winnerId 的第一个值是否为23,可以使用 lotto.winners.winnerId[0],写法如下:

@Test
void testGPath(){
    given().
    when().
            log().all().get("http://127.0.0.1:8000/restAssured.json").
    then().
            log().all()
            .body("lotto.winners.winnerId[0]",equalTo(23));
}

2)如果我们想要取某些相同字段中的最后一个,可以使用 -1 作为索引,例如断言断言 winners 数组下面的 winnerId 的最后一个的值是否为 54

@Test
void testGPath(){
    given().
    when().
            log().all().get("http://127.0.0.1:8000/restAssured.json").
    then().
            log().all()
            .body("lotto.winners.winnerId[-1]",equalTo(54));
}

findAll
有时候我们需要获取符合某些条件的结果来进行断言,这里 findAll 可以帮助我们实现,我们可以在 findAll 方法中写筛选条件,例如我们想取 winnerId 的值在大于或等于 30 小于 60 之间的结果进行断言,具体写法如下:

@Test
void testGPath(){
    given().
    when().
            log().all().get("http://127.0.0.1:8000/restAssured.json").
    then().
            log().all()
            .body("lotto.winners.findAll{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId[0]",equalTo(54));
}

find
find 的用法与 findAll 基本一致,只是 find 默认取匹配到的第一个:

@Test
void testGPath(){
    given().
    when().
            log().all().get("http://127.0.0.1:8000/restAssured.json").
    then().
            log().all()
            .body("lotto.winners.find{ winners -> winners.winnerId >= 30 && winners.winnerId < 60}.winnerId",equalTo(54));
    }

将上述各个断言语法写在一起,实际运行校验结果:

上面介绍了,GPath 也支持 XML 格式的断言,这里再以 rest-assured 官方给的一个实例做演示

<shopping>
 <category type="groceries">
 <item>
 <name>Chocolate</name>
 <price>10</price>
 </item>
 <item>
 <name>Coffee</name>
 <price>20</price>
 </item>
 </category>
 <category type="supplies">
 <item>
 <name>Paper</name>
 <price>5</price>
 </item>
 <item quantity="4">
 <name>Pens</name>
 <price>15</price>
 </item>
 </category>
 <category type="present">
 <item when="Aug 10">
 <name>Kathryn's Birthday</name>
 <price>200</price>
 </item>
 </category>
 </shopping>

再次在本地搭起一个临时服务:

若我们要对第二个 name 的值 Coffee 进行断言,写法如下:

@Test
void testXML(){
    when().
            get("http://127.0.0.1:8000/restAssured.xml").
    then().
            log().all().
            body("shopping.category[0].item[1].name",equalTo("Coffee"));
}

size()
可以利用 size() 方法来获取对应节点的数量,例如这里要断言 category 的数量:

@Test
void testXML(){
    when().
            get("http://127.0.0.1:8000/restAssured.xml").
    then().
            log().all()
            .body("shopping.category.size()",equalTo(3));
}

it.@type、it.price
在 xml中 断言中,可以利用 it. 属性或节点的值来作为筛选条件;
例如这里要获取 type 为 supplies 的 category 下的第一个 item 的 name,以及获取 price 为 10 的商品名 name。

@Test
void testXML(){
     when().
             get("http://127.0.0.1:8000/restAssured.xml").
     then().
             log().all()
             .body("shopping.category.findAll{ it.@type == 'supplies' }.item[0].name",equalTo("Paper"))
             .body("shopping.category.item.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
 }

.findAll
对于xml中有一个特别的语法,
.findAll,可以直接忽略前面的节点,直接对筛选条件进行匹配,依然获取price为10的商品名name,写法如下:

@Test
void testXML(){
    when().
            get("http://127.0.0.1:8000/restAssured.xml").
    then().
            log().all()
            .body("**.findAll{ it.price == 10 }.name",equalTo("Chocolate"));
}

将上述各个断言语法写在一起,实际运行校验结果:

1080×757 61.6 KB

在实际工作中,对接口返回值进行断言校验,除了常用字段的断言检测以外,还要对其他字段的类型进行检测,原因在于:

  • 返回字段较多,无法保证每个字段都写断言
  • 防止客户端未做 null 值的校验判断,如果因为版本变更或网络等原因造成某个不能接收 null 值的返回字段为 null,就很有可能造成软件的崩溃
  • 某些数值是不能为负的
  • 小数点保留位数,对于股票的交易、医疗数据的分析,小数点的精确度都是有其实际价值的

对返回的字段一个个写断言显然是非常耗时的,这个时候就需要一个模板,可以定义好数据类型和匹配条件,除了关键参数外,其余可直接通过此模板来断言,这个就要请出JsonSchema了

先对上述的 json 例子做少许修改,增加一个 String 类型的 winnername 字段,这里可以先你不用疑惑为什么加,后续自有其演示作用

1)首先要借助于Json schema tool的网站https://www.jsonschema.net/,将返回json字符串复制到页面左边,然后点击INFER SHCEMA,就会自动转换为schema json文件类型,会将每个地段的返回值类型都设置一个默认类型; 在pattern中也可以写正则进行匹配

2)点击“设置”按钮会出现各个类型返回值更详细的断言设置,这个就是schema最常用也是最实用的功能,也可以对每种类型的字段最更细化的区间值校验或者断言,例如长度,取值范围等,具体感兴趣的话可以从官网学习深入学习;平常对重要字段的校验我通常会选用其他断言,比如hamcrest断言

3)选择复制功能,可以将生成的schema模板保存下来

4)添加maven依赖,在rest-assured完成支持

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>4.0.0</version>
</dependency>

5)使用matchesJsonSchemaInClasspath方法对响应结果进行schema断言

@Test
void jsonSchemaTest(){
    get("http://127.0.0.1:8000/restAssured.json").
    then().log().all()
            .body(matchesJsonSchemaInClasspath("jsonSchema.json"));
}

运行结果:

  • String类型的默认值为null,后端很有可能在某个字段无值时返回null,例如我们将之前添加的winnername字段返回null:


运行查看断言结果:

1080×208 62 KB


很明显用例执行失败,当我们定义了winnername为String类型后,返回null就会断言失败,这显然不符合我们的需求,会造成用例执行结果的误判,这个时候我们需要使winnername即可以为String类型,又可以为null;

这就要用到jsonSchema提供的Combining schemas方法了 Combining schemas提供了如下几种方式:

  • allOf
  • anyOf
  • oneOf
  • not

这里我们选取anyOf(任何一项满足即可)来完成上述的举例,将原来的type换成String和null任何一个都支持的类型:


再次运行用例,查看断言结果:

用例完美通过,到此结束~

断言的语法不止上述列出的这些,但是日常工作中绝大部分需求都可以满足,如有需要可参考官方文档进去研究:

JsonPath:
JsonPath - json-path 5.3.0 javadoc
XmlPath:
XmlPath - xml-path 5.3.0 javadoc
JsonSchema:
Understanding JSON Schema — Understanding JSON Schema 2020-12 documentation

另外,在我们实际工作中,很多时候并不是直接对响应结果直接断言,我们可能需要获取响应结果中的某些值,将这些值传递到下一个接口或者和其他接口的响应进行比较断言,这就涉及到了对响应 response 的获取与处理了,后续文章继续探讨。

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

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

相关文章

好用的元数据管理工具是什么样

元数据是数据的“说明书”&#xff0c;元数据管理工具是企业数据治理的重要抓手&#xff0c;它可以帮助企业解决数据查找难、理解难等问题&#xff0c;促进数据的集成和共享。一个趁手的元数据管理工具是什么样的呢&#xff1f; 01 系统架构 从应用角度看&#xff0c;元数据管…

基于颜色直方图优化的图像增强方法

最近改图像颜色迁移的论文&#xff0c;审稿人要求补充基于直方图优化的方法细节。趁此机会&#xff0c;我重新下载了相关文献&#xff0c;决定重新学习下该类方法&#xff0c;并把一些细节记录在本篇博客中&#xff0c;供交流学习。 目录 1. 前言 2. 背景知识 3. 颜色变换 4. 颜…

若依源码分析(二)-登录流程源码分析

若依源码分析&#xff08;二&#xff09;-登录流程源码分析 本章节主要分析若依源码登录流程&#xff0c;一步一步走断点查看进入首页的全流程登录信息 1. 前台发起登录请求 http://127.0.0.1/dev-api/auth/login //auth表明这个请求走的是服务名称为auth的服务2. 后台处理流…

【虚幻引擎】UE4像素流推送PixelStreaming

一、前言 虚幻引擎像素流送&#xff08;Pixel Streaming&#xff09;允许你从任何有屏幕的联网设备&#xff08;例如计算机&#xff0c;手机&#xff0c;平板电脑等&#xff09;播放虚幻项目。在这个教程里&#xff0c;我们将学习如何激活虚幻引擎的像素流送并从任何Web浏览器控…

年尾结款,如何应对客户新的需求风险?

1、进行需求变更管理流程 需要提前建立需求基线&#xff0c;需求基线是需求变更的依据&#xff0c;并制定双方皆认可的需求变更流程。 在前期与用户签订合同时&#xff0c;可以增加一些相关条款&#xff0c;如限定用户提出需求变更的时间&#xff0c;规定何种情况的变更可以接受…

日期和时间的API

一、JDK8之前的日期和时间的API 1.System类中的currentTimeMillis() 返回当前时间与1970年1月1日0分0秒之间以毫秒为单位的时间差&#xff0c;称为时间戳 2.Java.util.Date类 |---java.sql.Date类 1.两个构造器的使用 >构造器一: Date(): 创建一个对应当前时间的Date对象…

CVE-2022-08475-DirtyPipe

前言CVE-2022-0847 DirtyPipe脏管道漏洞是Linux内核中的一个漏洞&#xff0c;该漏洞允许写只读文件&#xff0c;从而导致提权。调试环境• ubuntu 20.04• Linux-5.16.10• qemu-system-x86_64 4.2.1漏洞验证首先创建一个只读文件foo.txt&#xff0c;并且正常情况下是无法修改该…

2022年「博客之星」参赛博主:黛琳ghz

我正在参加年度博客之星评选&#xff0c;请大家帮我投票打分&#xff0c;您的每一分都是对我的支持与鼓励。五星必回&#xff0c;诚信互评&#xff0c;&#xff08;如果&#xff09;今日已满&#xff0c;明天必回&#xff0c;言出必行&#xff0c;感谢支持&#xff01; 我正在…

Protobuf:python版使用

目录 Protobuf详解 Python使用方式 下载protoc 编写.proto协议文件 编译Protocol buffer 存储/读取数据测试 Protobuf详解 深入 ProtoBuf - 简介 - 简书 (jianshu.com)[索引]文章索引 - 简书 (jianshu.com) Protobuf3语法详解 - 望星辰大海 - 博客园 (cnblogs.com) Pyth…

联芸科技冲刺科创板上市:业绩表现不稳定,实控人方小玲为美国籍

12月28日&#xff0c;联芸科技&#xff08;杭州&#xff09;股份有限公司&#xff08;下称“联芸科技”&#xff09;在上海证券交易所递交招股书&#xff0c;准备在科创板上市。 本次冲刺上市&#xff0c;联芸科技计划募资20.50亿元&#xff0c;其中4.66亿元用于新一代数据存储…

prophet模块学习总结-20221228

prophet模块的基本介绍及相关用法说明。 文章目录1.基本介绍Prophet包的特点2.Prophet 模型介绍2.1 长期趋势模型2.2 The Seasonality Function&#xff08;季节函数&#xff09;2.3 The Holiday/Event Function&#xff08;节日函数&#xff09;3.使用示例3.1 快速开始3.2 调节…

MetersPhere自动化解决用户登录问题+添加钉钉机器人

MetersPhere自动化解决用户登录问题添加钉钉机器人 现在遇到的问题&#xff0c;做自动化的时候几乎每个接口都需要token&#xff0c;这个token是登录获取的&#xff0c;那我有很多个自动化的场景&#xff0c;如果我每一个场景都加入登录接口&#xff0c;同时执行很多场景的时候…

骨传导耳机有用吗,最好用的骨传导耳机分享

骨传导耳机有没有用这个问题&#xff0c;主要还是看自己需要骨传导耳机的根本需求是什么&#xff0c;骨传导耳机更多的使用场景是在户外运动&#xff0c;但是日常才室内使用或者长时间使用的耳机爱好者&#xff0c;骨传导耳机也能在一定程度上保护听力&#xff0c;下面就分享五…

浅聊OpenHarmony

接触OpenHarmony快一年了&#xff0c;这里简单总结下自己对OpenHarmony的理解&#xff0c;如果有不对的地方&#xff0c;欢迎来讨论。OpenHarmony是什么&#xff1f;了解这个之前我们可以先来看看什么是开源&#xff1f; 一、开源是什么&#xff1f; 开源简单来讲&#xff0c…

阿里云视频点播资源迁移及回溯校验

阿里云视频点播资源迁移及回溯校验一&#xff1a;准备环境1.1、搭建springboot1.2、引入外部包二&#xff1a;表与配置2.1、拉取视频点播文件2.2、建表2.3、yml配置文件三&#xff1a;代码3.1、XML3.2、entity3.3、mapper3.4、Synchronize3.5、视频迁移Controller3.6、视频回溯…

Fedora初始化 | python在Fedora中的初始化搭建

本来是想玩一下ArticlePairMatching-master&#xff0c;结果需要graph-tool工具&#xff0c;这哥们需要c等环境&#xff0c;无法在window中直接安装。 望着不堪重负的win系统&#xff0c;还是安了一个全新的Fedora虚拟机作为实验环境吧。 1. 使用VMWare安装Fedora Fedora的图形…

户外徒步戴什么耳机比较好、最适合户外运动的五款耳机推荐

现在人们对自己的身体状态越来越重视了&#xff0c;无论是怎样的生活&#xff0c;一个健康的身体非常重要&#xff0c;近几年的运动健身热潮的兴起&#xff0c;能看出来人们会花更多的时间去锻炼自己的身体了&#xff0c;与之而来的就是各种健身、运动的蓝牙耳机不断的推陈出新…

2022餐馆设计最新十大排行榜(附餐馆设计案例图片)

随着生活水平的提升&#xff0c;人们对于用餐的环境要求越来越高&#xff0c;对于餐馆设计的要求随之提高&#xff0c;因此在装修时&#xff0c;很多餐饮老板想找一家实力强的餐厅设计公司&#xff0c;那么国内的餐饮设计公司数量庞大&#xff0c;有哪些擅长餐饮设计呢&#xf…

android生成javadoc

生成步骤 菜单 Tools -> Generate JavaDoc! 问题: 1.JavaDoc导出时出现乱码报错 错误: 编码GBK的不可映射字符 菜单 Tools -> Generate JavaDoc&#xff0c;弹出配置面板 在Other command line arguments 栏输入&#xff1a;-encoding utf-8 -charset utf-8 2.提示 程序…

C/S快速开发框架源码 winform快速开发框架源码

C/S系统开发框架源码 C#快速开发框架源码&#xff08;CS版&#xff09;00683 源码分享&#xff0c;需要源码学习可私信我。 系统功能&#xff1a; 该框架采用逻辑上的三层模式开发业务处理和数据处理完全分开&#xff0c;采用C#语言和MSSQL进行开发&#xff0c;主要实现了菜…