在上一篇文章中,我们初步探讨了 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"));
}

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

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

  • 返回字段较多,无法保证每个字段都写断言
  • 防止客户端未做 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:


运行查看断言结果:


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

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

  • allOf
  • anyOf
  • oneOf
  • not

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


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

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

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

JsonPath:
https://www.javadoc.io/doc/io.rest-assured/json-path/latest/io/restassured/path/json/JsonPath.html
XmlPath:
https://www.javadoc.io/doc/io.rest-assured/xml-path/latest/io/restassured/path/xml/XmlPath.html
JsonSchema:
https://json-schema.org/understanding-json-schema/

利器 | REST Assured 实践(二):断言实现相关推荐

  1. 软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲

    软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲 培训课程 Phthon Web开发 实训公司 XXX 总周数 3周

  2. P4语言编程快速开始 实践二

    参考:P4语言编程快速开始 上一篇系列博客:P4语言编程快速开始 实践二 Demo 2 本Demo所做的修改及实现的功能: 为simple_router添加一个计数器(counter),该计数器附加( ...

  3. ASP.NET MVC5 网站开发实践(二) Member区域 - 用户部分(2)用户登录、注销

    上次实现了用户注册,这次来实现用户登录,用到IAuthenticationManager的SignOut.SignIn方法和基于声明的标识.最后修改用户注册代码实现注册成功后直接登录. 目录: ASP ...

  4. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)

    原文:Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二) Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 ...

  5. Nginx反向代理与负载均衡应用实践(二)

    Nginx反向代理与负载均衡应用实践(二) 链接:https://pan.baidu.com/s/1xB20bnuanh0Avs4kwRpSXQ 提取码:migq 复制这段内容后打开百度网盘手机App ...

  6. SOLR7实践(二)--DIH配置及使用

    DIH配置及使用@SOLR7实践(二) DIH配置及使用 网上已经有很多相关文章了,但是实践中还是遇到了些问题,备忘一下. 一.配置solrconfig.xml 编辑/var/solr/data/ne ...

  7. Java内部类与异常类(上机实践二)

    Java内部类与异常类(上机实践二) 实践一 内部购物卷 手机专卖店为了促销自己的产品,决定发行内部购物券,但其他商场不能发行该购物券.编写一个 MobileShop 类(模拟手机专卖店),该类中有一 ...

  8. 《Python网络爬虫从入门到实践 第2版》第15章 爬虫实践二:知乎Live

    第15章 爬虫实践二:知乎Live 知乎是中文互联网一个非常大的知识社交平台.在知乎上,用户可以通过问答等交流方式获取知识.区别于百度知道等问答网站,知乎的回答往往非常深入,都是回答者精心写的,知乎上 ...

  9. Linux内核 实践二

    实践二 内核模块编译 20135307 张嘉琪 一.实验原理 Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合.之所以提供模块机制,是因为Linux本身是一个单内核.单内核由于所有内容 ...

  10. ROS理论与实践——二、ROS基础

    ROS理论与实践--二.ROS基础 前言 一.创建工作空间 1 什么是工作空间 2 创建流程 二.创建功能包 1 创建命令 2 创建流程 三.ROS通信编程 1 话题编程 1.1 话题编程流程 1.2 ...

最新文章

  1. Ubuntu apt-get install、apt-get -f install、apt-get --purge remove、apt-get update、apt-get upgrade、
  2. JS实现博客前端页面(一)—— 封装基础库
  3. OPENCV标定外参
  4. 北大AI公开课2019 | 雷鸣:人工智能革命与机遇
  5. 破坏双亲委派机制的那些事
  6. ftp协议是一种用于_______的协议_网络安全常见协议解析:TCP、UDP、HTTP、FTP、SMTP等之间的区别...
  7. Java DatagramPacket 中的坑
  8. Python入门--列表元素的判断及遍历,判断指定元素在列表中是否存在,列表元素的遍历,
  9. android自动化(appium)
  10. xcode 此工作区的项目包含使用Swift 3.x开发的源代码。此版本的Xcode不支持生成或迁移Swift 3.x目标。使用Xcode 10.1将代码迁移到Swift 4。
  11. python汉化包放哪_python环境搭建和pycharm的安装配置及汉化(零基础小白版)
  12. RHCSA-Day1 --- Linux介绍及环境搭建
  13. 小猪短租住房信息爬取
  14. linux temp文件夹在哪_linux基础知识笔记(第一天)
  15. 股票市场交易中的强化学习
  16. assert有什么作用
  17. R语言计算相关系数时出现NA的解决办法
  18. 单片机设计一个十字路口交通灯模拟控制系统(51单片机实训)
  19. Linux基础知识梳理
  20. Grub 命令行启动Windows全过程

热门文章

  1. 大数据可视化技术应用学习目标与复习小结
  2. Drupal迁移 | 如何创建一个Drupal 7 到 Drupal 9 的迁移路线图
  3. 2016年U盘启动盘制作工具哪个好用?看U盘启动盘排行榜!
  4. android音乐播放器横评,14款Android音乐播放器年度横评 安卓播放器对比测评
  5. three.js顶点篇
  6. 12306抢票,极限并发带来的思考?
  7. 如何提高国际短信到达率?
  8. CSS3阴影 box-shadow的使用和技巧总结
  9. word目录的制表符前导符无法改变
  10. 16代表啥_16代表的爱情恋爱含义 16代表什么爱情含义