1.json响应断言简介
前面的内容已经简单介绍了如何断言验证接口的响应值。在实际工作中,获取的json响应倪荣荣往往十分复杂,面对复杂的json响应体,可以用JSONPath对其进行解析。JSONPath提供了强大的解析json的功能,可以更便捷、灵活地解析json内容。
2.json响应断言环境准备
Python版本
pip install jsonpath
Java版本
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.6.0</version>
</dependency>
3.XPath和JSONPath语法
XPath和JSONPath语法有很多似之处,但还是有所不同。表7-1是XPath和JSONPath语法的对比。
| XPath | JSONPath | 描述 | |
|---|---|---|---|
| / | $ | 根节点对象/元素 | |
| . | @ | 当前的对象/元素 | |
| / | .or[] | 匹配下级元素 | |
| .. | n/a | 匹配上级元素,JSONPath不支持 | |
| // | .. | 递归方式匹配所有子元素 | |
| * | * | 通配符,匹配所有对象/元素,无论其名称如何 | |
| @ | n/a | 访问属性 | |
| [] | [] | 下标运算符,JSONPath从0开始 | |
| [,] | 连接的操作符,多个结果拼接成列表返回 | ||
| [] | ?() | 过滤器(脚本)表达式 | |
| n/a | () | 脚本表达式,使用基础脚本引擎 |
注:表中的一些语法符号相同,但作用是不一样的具体见表中的描述。
下面是一组json结构数据,分别通过JSONPath和XPath的方式提取出来。
{
"store":{
"book":[
{
"category":"reference",
"author":"Nigel Ress",
"title":"Sayings of the Century",
"price":8.95
},
{
"category":"fiction",
"author":"Evelyn Waugh",
"title":"Sword of Honour",
"price":12.99
},
{
"category":"fiction",
"author":"Herman Melville",
"title":"Moby Dick",
"isbn":"0-553-21311-3",
"price":8.99
},
{
"category":"fiction",
"author":"J. R. R. Tolkien",
"title":"The Lord of the Rings",
"isbn":"0-395-19395-8",
"price":22.99
}
],
"bicycle":{
"color":"red",
"price":19 95
}
}
}
表7-2列出了XPath与XPath与JSONPath表达式的对比。
| XPath | JSONPath | 结果 |
|---|---|---|
| /store/book/author | $.store.book[*].author | store中所有book的author |
| //author | $..author | 所有的author |
| /store/ | $.store.* | store中所有元素 |
| /store//price | $.store..price | store中所有的price |
| //book[3] | $..book[2] | book列表中的第三个 |
| //book[last()] | $..book[-1:] | book列表中的倒数第一个 |
| //book[position()<4] | $..book[:3] | book列表中的前两个 |
| //book[isbn] | $..book[?(@.isbn)] | 所有有isbn的book |
| //book[price<10] | $..book[?(@.peice<10)] | 所有价格低于10元的书 |
| //* | $..* | 所有json结构体中的元素 |
实例:想要获取store目录下的第一本书title
(1)XPath中的语法是:
/store/book[0]/title
(2)JSONPath的语法是:
$.s ore.book[0].itle
$['store']['book'][0]['title']
4.实战练习
以下是ceshiren.com/t/topic/695…这个接口的正常响应数据(因响应数据过大,删除了部分内容):
{
'pos _stream':{
'posts':[
{
'id':17126,
'name':'思寒',
'username':'seveniruby',
'avatar_template':'/user_avatar/ceshiren.com/seveniruby/{size}/2_2.png',
'created_at':'2020-10-02T04:23:30.586z',
'cooked':'<p>一直以来的平均涨薪率在30%以上,这次刷新的记录估计要保持好几年了</p>'
'post_number':6,
'post_type':1,
'updated_at':'2020-10-02T04:23:48.775z',
'reply_to_post_number':None,
'reads':651,
'readers_count':650,
'score':166.6,
'yours':False,
'topic_id':6950,
'topic_slug':'topic',
'display_username':'思寒',
'primary_group_name':'python_12',
//省略
},
],
},
'timeline_loolup':,
'suggested_topics':,
'tags':[
'精华帖',
'测试开发',
'测试求职',
'测试外包',
],
'id'=6950,
'title':'测试人生 | 从外包菜鸟到测试开发,薪资一年翻三倍,连自己都不相信!(附面试真题与答案)',
'fancy_title':'测试人生 | 从外包菜鸟到测试开发,薪资一年翻三倍,连自己都不敢信!(附面试真题与答案)',
}
通过使用JSONPath表达式获取以上响应内容中name字段为“思寒”所对应的cooked,且其中也包含“涨薪”的数据,并且做断言。
(1)Python演示代码
使用JSONPath表达式实现断言
import requests
from jsonpath import jsonpath
r = requests.get("https://ceshiren.com/t/topic/6950.json").json()
result = jsonpath(r, "$..posts[?(@.name == '思寒')].cooked")[1]
assert " 涨薪 " in result
(2)Java演示代码
使用JSONPath表达式实现断言
import com.jayway.jsonpath,jsonpath;
import org.junit.jupiter.api.Test;
import java.util.List;
import static io.restassured.RestAssured.given;
public class jsonTest{
@Test
void jsonTest(){
//获取响应信息,并转成字符串类型
String res = given().when().
get("https://ceshiren.com/t/topic/6950.json")
.then().extract().response().asString();
//通过JSONPath表达式提取需要的字段
List<String> result = JsonPath.read(res. "$..posts[?(@.name == '思寒')].cooked");
//断言验证
assert result.get(1).contains("涨薪");
}
}
搜索微信公众号:TestingStudio霍格沃兹的干货都很硬核