技術(shù)分享 | 接口自動(dòng)化測(cè)試如何搞定 json 響應(yīng)斷言?
在之前的的章節(jié)已經(jīng)簡(jiǎn)單介紹了如何斷言接口的響應(yīng)值,在實(shí)際工作過(guò)程中,json 的響應(yīng)內(nèi)容往往十分復(fù)雜,面對(duì)復(fù)雜的 json 響應(yīng)體,主要通過(guò) JSONPath 解決。JSONPath 提供了強(qiáng)大的 JSON 解析功能,使用它自帶的類(lèi)似 XPath 的語(yǔ)法,可以更便捷靈活的用來(lái)獲取對(duì)應(yīng)的 JSON 內(nèi)容。
***環(huán)境準(zhǔn)備***
Python 版本安裝
```
pip install jsonpath
```
Java 版本安裝
```
<dependency>
? ? <groupId>com.jayway.jsonpath</groupId>
? ? <artifactId>json-path</artifactId>
? ? <version>2.6.0</version>
</dependency>
```
***XPath 和 JSONPath 語(yǔ)法***
下表是 XPath 和 JSONPath 語(yǔ)法進(jìn)行對(duì)比,這兩者的定位方式,有著非常多的相似之處:

比如同樣一個(gè)字段,XPath 中的語(yǔ)法是:
```
/store/book[0]/title
```
JSONPath 的語(yǔ)法是:
```
$.store.book[0].title
$['store']['book'][0]['title']
```
下面是一組 json 結(jié)構(gòu),分別通過(guò) JSONPath 和 XPath 的方式提取出來(lái)
```
{
? "store": {
? ? "book": [
? ? ? {
? ? ? ? "category": "reference",
? ? ? ? "author": "Nigel Rees",
? ? ? ? "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
? ? }
? }
}
```
下表列出了 XPath 與 JSONPath 的對(duì)比:

***實(shí)戰(zhàn)練習(xí)***
以下是 https://ceshiren.com/t/topic/6950.json 這個(gè)接口的正常響應(yīng)值(因響應(yīng)篇幅過(guò)長(zhǎng),刪除了部分內(nèi)容):
```
{
? 'post_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>一直以來(lái)的平均漲薪率在30%以上,這次刷新的記錄估計(jì)要保持好幾年了</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_lookup': ,
? 'suggested_topics':,
? 'tags': [
? ? '精華帖',
? ? '測(cè)試開(kāi)發(fā)',
? ? '測(cè)試求職',
? ? '外包測(cè)試'
? ],
? 'id': 6950,
? 'title': '測(cè)試人生 | 從外包菜鳥(niǎo)到測(cè)試開(kāi)發(fā),薪資一年翻三倍,連自己都不敢信?。ǜ矫嬖囌骖}與答案)',
? 'fancy_title': '測(cè)試人生 | 從外包菜鳥(niǎo)到測(cè)試開(kāi)發(fā),薪資一年翻三倍,連自己都不敢信!(附面試真題與答案)',
}
```
接下來(lái)則需要實(shí)現(xiàn)一個(gè)請(qǐng)求,斷言以上的響應(yīng)內(nèi)容中 name 字段為'思寒'所對(duì)應(yīng)的 cooked 包含"漲薪"
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
```
?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() {
? ? ? ? //獲取響應(yīng)信息,并轉(zhuǎn)成字符串類(lèi)型
? ? ? ? String res = given().when().
? ? ? ? ? ? ? ? get("https://ceshiren.com/t/topic/6950.json")
? ? ? ? ? ? ? ? .then().extract().response().asString();
? ? ? ? //通過(guò)jsonpath表達(dá)式提取需要的字段
? ? ? ? List<String> result = JsonPath.read(res, "$..posts[?(@.name == '思寒')].cooked");
? ? ? ? // 斷言驗(yàn)證
? ? ? ? assert result.get(1).contains("漲薪");
? ? }
}
```