深入解析Python中的JSON比較
前言
進(jìn)行接口自動(dòng)化時(shí),有時(shí)候我們需要斷言的數(shù)據(jù)比較多,一個(gè)字段一個(gè)字段進(jìn)行斷言比較麻煩,如果可以直接斷言整個(gè)響應(yīng)結(jié)果,豈不美哉,那該如何實(shí)現(xiàn)該功能呢?
遞歸
在進(jìn)入正式實(shí)現(xiàn)前,我們先簡(jiǎn)單說一下遞歸。因?yàn)樵摴δ芪覀冎饕褂眠f歸實(shí)現(xiàn),以防小伙伴們看不懂。
是什么?
遞歸是一種算法或函數(shù)設(shè)計(jì)方法,它通過將一個(gè)問題不斷分解成規(guī)模更小的子問題來解決原始問題。在 Python 中,遞歸是一種函數(shù)自身調(diào)用自身的過程。通過遞歸,程序可以在問題空間中向下深入,并通過返回值將解決子問題的結(jié)果合并起來,最終獲得整個(gè)問題的解。
如何用?
在 Python 中使用遞歸,首先需要定義邊界條件,即遞歸的結(jié)束條件。當(dāng)滿足邊界條件時(shí),遞歸停止,返回結(jié)果。同時(shí),還需要定義遞歸情況,即在未滿足邊界條件時(shí),如何繼續(xù)遞歸調(diào)用函數(shù)來解決子問題。遞歸函數(shù)應(yīng)該能夠?qū)栴}領(lǐng)域縮小,使其逐漸接近邊界條件。
隱藏風(fēng)險(xiǎn)
首先,遞歸可能會(huì)導(dǎo)致堆棧溢出,特別是在處理大規(guī)模問題時(shí)。其次,遞歸的執(zhí)行效率可能較低,因?yàn)槊看芜f歸都需要保存函數(shù)調(diào)用的上下文。此外,遞歸需要合理設(shè)置邊界條件,否則可能導(dǎo)致無限循環(huán)和程序崩潰。
在編寫遞歸函數(shù)時(shí),需要仔細(xì)考慮邊界條件和遞歸情況,確保遞歸能夠正確結(jié)束,并得到期望的結(jié)果。同時(shí),為了提高遞歸性能,可以考慮使用尾遞歸優(yōu)化或迭代等技術(shù)。
案例實(shí)現(xiàn)
有了遞歸的基本了解,接下來進(jìn)入正題,我們將實(shí)現(xiàn)如何斷言整個(gè)接口響應(yīng)數(shù)據(jù)。
class AssertInfo: ? ?data = [] ? ? def diff_json(response_data, assert_data): ? ?if isinstance(response_data, dict): ? ? ? ?for key in assert_data: ? ? ? ? ? ?if key not in response_data: ? ? ? ? ? ? ? ?info = f"Response data has no key: {key}" ? ? ? ? ? ? ? ?print(info) ? ? ? ? ? ? ? ?AssertInfo.data.append(info) ? ? ? ?for key in response_data: ? ? ? ? ? ?if key in assert_data: ? ? ? ? ? ? ? ?diff_json(response_data[key], assert_data[key]) ? ? ? ? ? ?else: ? ? ? ? ? ? ? ?info = f"Assert data has not key: {key}" ? ? ? ? ? ? ? ?print(info) ? ?elif isinstance(response_data, list): ? ? ? ?if len(response_data) == 0: ? ? ? ? ? ?print("response is []") ? ? ? ?if len(response_data) != len(assert_data): ? ? ? ? ? ?print(f"list len: '{len(response_data)}' != '{len(assert_data)}'") ? ? ? ? ?if response_data: ? ? ? ? ? ?if isinstance(response_data[0], dict): ? ? ? ? ? ? ? ?response_data = sorted(response_data, key=lambda x: x[list(response_data[0].keys())[0]]) ? ? ? ? ? ?else: ? ? ? ? ? ? ? ?response_data = sorted(response_data) ? ? ? ?if assert_data: ? ? ? ? ? ?if isinstance(assert_data[0], dict): ? ? ? ? ? ? ? ?assert_data = sorted(assert_data, key=lambda x: x[list(assert_data[0].keys())[0]]) ? ? ? ? ? ?else: ? ? ? ? ? ? ? ?assert_data = sorted(assert_data) ? ? ? ? ?for src_list, dst_list in zip(response_data, assert_data): ? ? ? ? ? ?diff_json(src_list, dst_list) ? ?else: ? ? ? ?if str(response_data) != str(assert_data): ? ? ? ? ? ?info = f"Value are not equal: {response_data}" ? ? ? ? ? ?print(info) ? ? ? ? ? ?AssertInfo.data.append(info)
代碼其實(shí)也不難理解,我們做一個(gè)簡(jiǎn)單解釋:
這是一個(gè)用于比較兩個(gè) JSON 數(shù)據(jù)格式是否相同的函數(shù)。每個(gè)部分的功能:
1.函數(shù)名稱:diff_json(response_data, assert_data)
參數(shù):response_data
是接口響應(yīng)數(shù)據(jù),assert_data
是期望的斷言數(shù)據(jù)。
2.if isinstance(response_data, dict):
如果 response_data
是字典類型,則進(jìn)入該條件判斷。
循環(huán)遍歷 assert_data
中的每個(gè)鍵(key):
如果鍵(key)不在 response_data
中,則打印信息表示響應(yīng)數(shù)據(jù)缺少該鍵(key)。
循環(huán)遍歷 response_data
中的每個(gè)鍵(key):
- 如果鍵(key)在
assert_data
中,則遞歸調(diào)用diff_json
函數(shù)進(jìn)行比較。 - 否則,打印信息表示斷言數(shù)據(jù)缺少該鍵(key)。
3.elif isinstance(response_data, list):
如果 response_data
是列表類型,則進(jìn)入該條件判斷。
檢查響應(yīng)數(shù)據(jù)和斷言數(shù)據(jù)的長(zhǎng)度是否相等,如果不相等,則打印信息表示長(zhǎng)度不一致。
如果 response_data
不為空:
- 如果列表中的元素是字典類型,按照字典鍵(key)的值進(jìn)行排序。
- 如果列表中的元素不是字典類型,進(jìn)行普通的排序。
如果 assert_data
不為空:
- 如果列表中的元素是字典類型,按照字典鍵(key)的值進(jìn)行排序。
- 如果列表中的元素不是字典類型,進(jìn)行普通的排序。
使用 zip
函數(shù)同時(shí)迭代 response_data
和 assert_data
:
對(duì)于每個(gè)對(duì)應(yīng)位置的元素,遞歸調(diào)用 diff_json
函數(shù)進(jìn)行比較。
4.else:
- 如果
response_data
既不是字典類型也不是列表類型,則進(jìn)入該條件判斷。 - 如果
response_data
和assert_data
的值不相等,則打印信息表示值不相等。
這個(gè)函數(shù)通過遞歸的方式,遍歷并比較兩個(gè) JSON 數(shù)據(jù)結(jié)構(gòu)的每一個(gè)鍵(key)和值。如果存在差異,將會(huì)打印出對(duì)應(yīng)的信息。在需要斷言和驗(yàn)證接口返回?cái)?shù)據(jù)時(shí),可以使用該函數(shù)進(jìn)行檢查。
好了,那我們看一看測(cè)試效果:
response_data = { ? ?"name": "Alice", ? ?"age": 25, ? ?"email": "alice@example.com" } ? assert_data = { ? ?"name": "Alice", ? ?"email": "Alice@example.com" } ? diff_json(response_data, assert_data)
執(zhí)行之后,會(huì)打印出如下結(jié)果:
Assert data has not key: age
Value are not equal: alice@example.com
完美解決!
最后
這個(gè)功能還是很實(shí)用的,大部分接口響應(yīng)內(nèi)容都比較復(fù)雜,想要斷言的內(nèi)容比較多時(shí)就比較麻煩,而這個(gè)函數(shù)可以比較兩個(gè) JSON 數(shù)據(jù)格式是否相同,節(jié)省了很多時(shí)間,提高編寫接口用例的效率。
到此這篇關(guān)于深入解析Python中的JSON比較的文章就介紹到這了,更多相關(guān)Python JSON內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python pyttsx3庫(kù)實(shí)現(xiàn)文本轉(zhuǎn)語音功能的示例
pyttsx3是一個(gè)功能強(qiáng)大且易于使用的文本轉(zhuǎn)語音庫(kù),適合需要離線語音合成的場(chǎng)景,本文就來介紹一下Python pyttsx3庫(kù)實(shí)現(xiàn)文本轉(zhuǎn)語音功能的示例,感興趣的可以了解一下2025-04-04Python基礎(chǔ)學(xué)習(xí)之基本數(shù)據(jù)結(jié)構(gòu)詳解【數(shù)字、字符串、列表、元組、集合、字典】
這篇文章主要介紹了Python基礎(chǔ)學(xué)習(xí)之基本數(shù)據(jù)結(jié)構(gòu),結(jié)合實(shí)例形式分析了Python數(shù)字、字符串、列表、元組、集合、字典等基本數(shù)據(jù)類型功能、原理及相關(guān)使用技巧,需要的朋友可以參考下2019-06-06Python Web框架之Django框架Form組件用法詳解
這篇文章主要介紹了Python Web框架之Django框架Form組件用法,結(jié)合實(shí)例形式詳細(xì)分析了Django框架中各種常用Form組件的功能、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-08-08簡(jiǎn)單了解python gevent 協(xié)程使用及作用
這篇文章主要介紹了簡(jiǎn)單了解python gevent 協(xié)程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07如何解決pycharm調(diào)試報(bào)錯(cuò)的問題
在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于如何解決pycharm調(diào)試報(bào)錯(cuò)的問題文章,需要的朋友們可以學(xué)習(xí)參考下。2020-08-08python中的iterator和"lazy?iterator"區(qū)別介紹
這篇文章主要介紹了python中的iterator和?“l(fā)azy?iterator“之間有什么區(qū)別,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04