接口自動(dòng)化測試,一鍵快速校驗(yàn)接口返回值全部字段
關(guān)注上方“測試開發(fā)技術(shù)”,選擇星標(biāo),
干貨技術(shù),第一時(shí)間送達(dá)!

大家好,我是狂師。
在日常開展自動(dòng)化測試工作時(shí),為了保證接口測試的有效性,少不了要對接口返回的響應(yīng)字段進(jìn)行校驗(yàn)、斷言等操作。當(dāng)接口返回的字段數(shù)量本身就很少時(shí),接口斷言操作一般都很容易就能實(shí)現(xiàn),但當(dāng)接口的返回字段特別多,結(jié)構(gòu)特別復(fù)雜時(shí),例如響應(yīng)字段數(shù)量達(dá)到了成百上千時(shí),如何快速實(shí)現(xiàn)全部返回字段的校驗(yàn)?這類問題,相信困擾了很多的正在開展接口測試的小伙伴。
今天針對如何快速審核接口返回值全部字段問題,分享一些解答思路,希望能幫到大家~
其實(shí)解決上述之類問題,市面上常見的解決方案有兩類:
根據(jù)業(yè)務(wù)校驗(yàn)需求,自定義開發(fā)校驗(yàn)規(guī)則庫 借助現(xiàn)有的第三方庫
今天,我們先來聊聊,如何借助現(xiàn)有的第三方庫來解決: 快速校驗(yàn)API接口返回的全部字段。由于當(dāng)今大部分接口都是基于Restful API,后續(xù)我介紹中,我們假設(shè)接口響應(yīng)體格式以JSON為例。
要滿足上面的實(shí)現(xiàn)需求,第三方庫方案有很多,比如常見的就有:deepdiff、difflib、json-diff、json_tools 等,這些三方庫之間,都有各自側(cè)重點(diǎn),本篇文章,重點(diǎn)介紹:如何借助DeepDiff庫來解決快速校驗(yàn)接口返回字段的問題。
一、認(rèn)識(shí)一下,DeepDiff 介紹
Deepdiff模塊常用來校驗(yàn)兩個(gè)對象是否一致,并找出其中差異之處。其中提供了三個(gè)類,DeepDiff,DeepSearch和DeepHash,官網(wǎng)地址:https://deepdiff.readthedocs.io/en/latest/ ,當(dāng)前最新版本為:V5.5.0

主要組成部分:
DeepDiff:比較兩個(gè)對象,對象可以是字段、字符串等可迭代的對象,針對對象的深層差異,遞歸查找所有更改。
DeepSearch:在對象中搜索其他對象
DeepHash:根據(jù)對象的內(nèi)容進(jìn)行哈希處理
DeepDiff 的初衷是用來找出不同數(shù)據(jù)的差別,可以比較JSON、XML文本類的,也可以比較圖片,在使用了一下之后,其實(shí)我們完全可以直接使用它作為測試的斷言,這也是從另一個(gè)思考角度提供了一種全新的校驗(yàn)思路。
二、DeepDiff 使用
當(dāng)你看完上述的介紹,相信還是一臉懵,不知如何下手,接下來,就通過幾個(gè)案例來進(jìn)一步感受一下Deepdiff的功能和作用。
使用之前,先安裝:
pip install deepdiff
2.1 案例一:比較兩個(gè)JSON
利用Deepdiff 比較 JSON 的差異:
import pytest
import requests
import pprint
from deepdiff import DeepDiff
class TestDemo(object):
def test_case_01(self):
a = {"Object": {
"code": "0",
"message": "success"
},
"code": "0",
"message": "success"
}
b = {"Object": {
"code": "0",
"message": "failure"
},
"message": "success",
"timestamp": "1614301293"
}
pprint.pprint(DeepDiff(a, b))
上述案例,作用是比較a和b兩者的差異,result 差異的輸出結(jié)果是:
.{'dictionary_item_added': [root['timestamp']],
'dictionary_item_removed': [root['code']],
'values_changed': {"root['Object']['message']": {'new_value': 'failure',
'old_value': 'success'}}}
上述輸出結(jié)果中,實(shí)際上根據(jù)這個(gè)返回的 json 獲取所有的差別。主要是對比對象之間的值、類型前后之間的變化以及刪除的或者增加的情況key進(jìn)行了結(jié)果輸出。
主要包含以下四種情況:
1、type_changes:類型改變的key 2、values_changed:值發(fā)生變化的key 3、dictionary_item_added:字典key添加 4、dictionary_item_removed:字段key刪除
2.2 案例二:比較接口響應(yīng)
有了案例一的基礎(chǔ),進(jìn)一步,我們將本地定義寫死的變量值改成采取調(diào)用接口的方式(更符合實(shí)際接口測試),通過發(fā)起請求,獲取響應(yīng)、并結(jié)合Deepdiff來斷言使用。
核心思路:先定義預(yù)期的響應(yīng)結(jié)構(gòu)體(意味著,你得事先知道你期望的結(jié)果是什么),再根據(jù)實(shí)際返回的結(jié)構(gòu)體兩者通過Deepdiff進(jìn)行自動(dòng)比較。
import pytest
import requests
import pprint
from deepdiff import DeepDiff
class TestDemo(object):
def setup_class(self):
self.response = requests.get('http://www.httpbin.org/json').json()
def test_case_02(self):
expected_reps = {'slideshow': {'author': 'Yours Truly', 'date': 'date of publication',
'slides': [{'title': 'Wake up to WonderWidgets!', 'type': 'all'}, {
'items': ['Why <em>WonderWidgets</em> are great',
'Who <em>buys</em> WonderWidgets'], 'title': 'Overview',
'type': 'all'}], 'title': 'Sample Slide Show'}}
pprint.pprint(DeepDiff(expected_reps, self.response))
由于實(shí)際返回的結(jié)構(gòu)體和預(yù)期定義待校驗(yàn)的結(jié)構(gòu)體數(shù)據(jù)完全一樣,因此上述代碼輸出結(jié)果為:{},即兩者沒有差異。(也意味著實(shí)際和預(yù)期結(jié)果一致)
在此基礎(chǔ)上,如果我們把上述expected_reps預(yù)期結(jié)構(gòu)體中的author由Yours Truly修改為Yours,再執(zhí)行一次,則輸出的結(jié)果為:
{'values_changed': {"root['slideshow']['author']": {'new_value': 'Yours Truly',
'old_value': 'Yours'}}}
從上述的輸出結(jié)果中,我們可以很明顯的獲取到三個(gè)訊息:
接口返回的結(jié)構(gòu)體中有值發(fā)生了改變,通過 values_changed標(biāo)識(shí)出來了明確指出具體哪個(gè)字段的值發(fā)生改變了,如 root['slideshow']['author']。改變具體的內(nèi)容,如實(shí)際返回值為 Yours Truly,而預(yù)期值為Yours。
看完了這個(gè),相信此時(shí)的你,對Deepdiff在接口測試中的使用,已經(jīng)有了一些感覺了。但接著你肯定會(huì)提出疑問,有些接口返回的值,并不是固定的,那比如校驗(yàn)?zāi)?。比如某個(gè)時(shí)間戳字段,每次調(diào)用接口時(shí),返回字段的值都是不一樣,針對這類只知道數(shù)據(jù)規(guī)則,但數(shù)據(jù)本身的值一開始是無法確定的,又該如何結(jié)合Deepdiff來使用呢?別急,再接著往下看。
2.3 案例三:正則搜索匹配
要解決上述的問題,可以利用DeepSearch中的正則搜索匹配功能,如果你的接口返回,是一個(gè)很深的嵌套結(jié)構(gòu)對象,然后你想校驗(yàn)查找指定的元素(key和value都行)是否存在,那么Deep Search將是個(gè)好選擇。
使用前,需要先導(dǎo)入from deepdiff import grep,示例源碼如下:
def test_case_03(self):
datas = {"mikezhou": "狂師", "age":18, "city": "china", "info": {"author": {"tag": "mikezhou"}}}
reuslt = datas | grep("mike*",use_regexp=True)
print(reuslt)
比如想校驗(yàn)有沒有以mike開頭字段或值在返回的結(jié)構(gòu)體中,指定元素存在則返回它的路徑;不存在則返回一個(gè)空字典。上述輸出結(jié)果如下:
.{'matched_paths': ["root['mikezhou']"], 'matched_values': ["root['info']['author']['tag']"]}
上述示例雖簡單,但如果你足夠聰明,相信應(yīng)該已經(jīng)能從中Get核心思路了:針對一些動(dòng)態(tài)事先無法預(yù)料的值,可以通過借助正則表達(dá)式來匹配校驗(yàn),具體如何校驗(yàn),取決于你的正則表達(dá)式如何描述。
三、小技巧:DeepDiff 黑名單
在實(shí)際做接口測試斷言時(shí),有時(shí)對象順序不一樣,但是實(shí)際情況兩個(gè)值還是一樣的,或者是針對全量字段校驗(yàn)時(shí),想跳過一些特殊的字段校驗(yàn)(類似黑名單一樣,將不需要校驗(yàn)的字段,明確指出),為了解決這類問題,Deepdiff也提供了相信的參數(shù),只需要在比較的時(shí)候加入:
ignore order(忽略排序)ignore string case(忽略大小寫)exclude_paths字段黑名單排除參數(shù)即可,原型如下:
result = DeepDiff(result, expected, view='tree',ignore_order=True,ignore_string_case=True)
示例:
def test_case_05(self):
expected_reps = {"datas": {
"code": "200",
"message": "success"
},
"code": "201",
"message": "success"
}
actual_reps = {"datas": {
"code": "201",
"message": "failure"
},
"message": "Success",
"timestamp": "1614301293"
}
pprint.pprint(DeepDiff(expected_reps, actual_reps, ignore_order=True,ignore_string_case=True,exclude_paths={"root['timestamp']"}))
上述示例代碼,忽略了排序規(guī)則、大小寫問題,并且指定排除timestamp字段校驗(yàn)。具體的輸出結(jié)果如下:
{'dictionary_item_removed': [root['code']],
'values_changed': {"root['datas']['code']": {'new_value': '201',
'old_value': '200'},
"root['datas']['message']": {'new_value': 'failure',
'old_value': 'success'},
"root['message']": {'new_value': 'Success',
'old_value': 'success'}}}
四、小結(jié)
通過上述的案例介紹,相信你對DeepDiff的使用有了一個(gè)基本認(rèn)識(shí)。在接口自動(dòng)化測試中,小結(jié)一下,使用 DeepDiff 的好處有:
接口測試的時(shí)候,可以直接利用預(yù)期結(jié)構(gòu)體(或者稱之為接口契約)與實(shí)際返回的結(jié)構(gòu)體(字段、值)進(jìn)行自動(dòng)比較,來確定是不是一樣,可以少寫很多代碼。 數(shù)據(jù)庫數(shù)據(jù)比較的時(shí)候也是一樣可以,使用 SQL查出結(jié)果之后,直接變成 JSON就可以和期望的 JSON對比了。
本文旨在從另一個(gè)視角幫大家提供一些接口測試全量字段校驗(yàn)的解決思路,更多關(guān)于Deepdiff使用技巧,以及更優(yōu)解的全量字段解決方案(還有很多),歡迎大家積極探索。
如果你覺得文章還不錯(cuò),幫忙 點(diǎn)贊、轉(zhuǎn)發(fā)、關(guān)注、留言 ,因?yàn)檫@將是公號(hào)持續(xù)輸出更多優(yōu)質(zhì)文章的最強(qiáng)動(dòng)力!本篇點(diǎn)贊超過30+,下個(gè)月將有驚喜~
(點(diǎn)擊直達(dá)小程序)
END

長按二維碼/微信掃碼 添加作者
備注回復(fù)【接口測試】

