Python全字段断言之DeepDiff模块详解

 更新时间:2023年08月21日 11:34:35   作者:shines_m  
这篇文章主要介绍了Python全字段断言之DeepDiff模块详解,Python中也提供了deepdiff库,常用来校验两个对象是否一致,包含3个常用类,DeepDiff,DeepSearch和DeepHash,,需要的朋友可以参考下

一、简介

工作中我们经常要两段代码的区别,或者需要查看接口返回的字段与预期是否一致。

Python中也提供了deepdiff库,常用来校验两个对象是否一致,包含3个常用类,DeepDiff,DeepSearch和DeepHash

其中DeepDiff最常用,可以对字典,可迭代对象,字符串等进行对比,使用递归地查找所有差异。

也可以用来校验多种文件内容的差异,如txt、json、图片等…

DeepDiff库常用来校验两个对象是否一致,并找出其中差异之处。

安装:

pip install deepdiff

二、DeepDiff模块

1.deepdiff常用操作

如果实际请求结果和预期值的json数据都一致,那么会返回{}空字典,否则会返回对比差异的结果,接口测试中我们也可以根据这个特点进行断言。

如果对比结果不同,将会给出下面对应的返回:

  • type_changes:类型改变的key
  • values_changed:值发生变化的key
  • dictionary_item_added:字典key添加
  • dictionary_item_removed:字段key删除

2.代码示例

2.1 对比txt文件

from deepdiff import DeepDiff
# 对比file文件
f1, f2 = open('./data/a.txt', 'r', encoding='utf-8').read(), open('./data/b.txt', 'r', encoding='utf-8').read()
print(DeepDiff(f1, f2))

输出:
{'values_changed': {'root': {'new_value': 'abcd', 'old_value': 'abc'}}}

2.2 对比json

from deepdiff import DeepDiff
# 对比json文件
json1={
    'code': 0,
    "message": "成功",
    "data": {
    "total": 28,
    "id":123
    }
}
json2={
    'code':0,
    "message":"成功",
    "data": {
    "total": 29,
    }
}
print(DeepDiff(json1, json2))

# 输出结果,id移除,total值发生改变
{'dictionary_item_removed': [root['data']['id']], 'values_changed': {"root['data']['total']": {'new_value': 29, 'old_value': 28}}}

2.3 DeepDiff在Pytest框架中的应用

注意,对比的报文必须是字典格式!!!

from deepdiff import DeepDiff
import pytest
import requests
# DeepDiff在Pytest框架中的应用, 注意,对比的报文必须是字典格式!!!
class TestCase:
    expect = {
        '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'
        }
}
    def setup(self):
        # 返回字典格式报文
        self.response = requests.get('http://www.httpbin.org.json').json()
    def test_case_01(self):
        print('用例对比结果:')
        print(DeepDiff(self.response, self.expect))
    def test_case_02(self):
        print('用例对比结果:')
        print(DeepDiff(self.response['slideshow']['author'], 'Yours Truly1'))
if __name__ == '__main__':
    pytest.main(['-s'])

输出:
PASSED                          [ 50%]用例对比结果:
{}
PASSED                          [100%]用例对比结果:
 {'values_changed': {'root': {'new_value': 'Yours Truly1', 'old_value': 'Yours Truly'}}}

其实,在实际接口断言中,可能需要校验的字段顺序不一样,又或者有一些字段值不需要,为了解决这类问题,Deepdiff也提供了相信的参数,只需要在比较的时候加入,传入对应参数即可。

  • ignore order(忽略排序)
  • ignore string case(忽略大小写)
  • exclude_paths排除指定的字段

代码中 使用:

print(DeepDiff(self.response,
self.expect,view='tree',ignore_order=True,ignore_string_case=True,exclude_paths=
{"root['slideshow']['date']"}))

3.参数介绍

3.1 展示差异的深度

cutoff_distance_for_pairs: (1 >= float > 0,默认值=0.3)

此参数通常结合ignore_order=true使用,用于结果中展示差异的深度。

值越大,则结果中展示的差异深度越大。

from deepdiff import DeepDiff
t1 = [[[1.0]]]
t2 = [[[20.0]]]
print(DeepDiff(t1, t2, ignore_order=True, cutoff_distance_for_pairs=0.3))
print(DeepDiff(t1, t2, ignore_order=True, cutoff_distance_for_pairs=0.2))
print(DeepDiff(t1, t2, ignore_order=True, cutoff_distance_for_pairs=0.1))

输出:
{'values_changed': {'root[0][0][0]': {'new_value': 20.0, 'old_value': 1.0}}}
{'values_changed': {'root[0][0]': {'new_value': [20.0], 'old_value': [1.0]}}}
{'values_changed': {'root[0]': {'new_value': [[20.0]], 'old_value': [[1.0]]}}}

3.2 ignore types

1)ignore_string_type_changes

默认=False,默认忽略字符串类型的更改。如果ignore_string_type_changes=True,则b"Hello" 与 “Hello”被认为是相同的。

print(DeepDiff(b'hello', 'hello'))
print(DeepDiff(b'hello', 'hello', ignore_string_type_changes=True))

输出:
{'type_changes': {'root': {'old_type': <class 'bytes'>, 'new_type': <class 'str'>, 'old_value': b'hello', 'new_value': 'hello'}}}
 {}

2)ignore_numeric_type_changes

默认=False,表示忽略数值类型更改。设置为true时,则认为10和10.0是相同的

PS:此参数仅作用与numbers对象比较,如果拿numers和string比较则不生效

from deepdiff import DeepDiff
from decimal import Decimal
t1 = Decimal('10.01')
t2 = 10.01
print(DeepDiff(t1, t2))
print(DeepDiff(t1, t2, ignore_numeric_type_changes=True))

输出:
{'type_changes': {'root': {'old_type': <class 'decimal.Decimal'>, 'new_type': <class 'float'>, 'old_value': Decimal('10.01'), 'new_value': 10.01}}}
 {}

3.3 view

DeepDiff支持对比结果选择text视图和tree视图展示。

主要区别在于, tree视图具有遍历对象的功能,可以看到哪些对象与哪些其他对象进行了比较。

虽然视图选项决定了输出的格式,但无论你选择哪种视图,你都可以通过使用pretty()方法得到一个更适合阅读的输出

t1= {"name": "yanan", "pro": {"sh": "shandong", "city": ["zibo", "weifang"]}}
t2 = {"name": "changsha", "pro": {"sh": "shandong", "town": ["taian", "weifang"]}}
ddiff = DeepDiff(t1, t2, view='tree')
print(ddiff)
# 默认为text
ddiff = DeepDiff(t1, t2, view='text')
print(ddiff)

输出:
 {'dictionary_item_added': [<root['pro']['town'] t1:not present, t2:['taian', 'w...]>], 'dictionary_item_removed': [<root['pro']['city'] t1:['zibo', 'we...], t2:not present>], 'values_changed': [<root['name'] t1:'yanan', t2:'changsha'>]}
 {'dictionary_item_added': [root['pro']['town']], 'dictionary_item_removed': [root['pro']['city']], 'values_changed': {"root['name']": {'new_value': 'changsha', 'old_value': 'yanan'}}}

3.4 pretty( ) 方法

使用pretty( ) 方法获得更可读的输出, 无论你使用什么视图来生成结果

t1= {"name": "yanan", "pro": {"sh": "shandong", "city": ["zibo", "weifang"]}}
t2 = {"name": "changsha", "pro": {"sh": "shandong", "town": ["taian", "weifang"]}}
print(DeepDiff(t1, t2, view='tree').pretty())
print(DeepDiff(t1, t2, view='text').pretty())

 输出:
Item root['pro']['town'] added to dictionary.
Item root['pro']['city'] removed from dictionary.
Value of root['name'] changed from "yanan" to "changsha".

Item root['pro']['town'] added to dictionary.
Item root['pro']['city'] removed from dictionary.
Value of root['name'] changed from "yanan" to "changsha".

大家在比较两个数据对象的时候,更多遇到的场景是:key值不同、key新增、key减少、key值类型改变、结构不同

t1 = {
'Author': '河马',
'wechat': 'ZZ666'
}
t2 = {
'Author': '河马',
'wechat': 'ZZ666',
'Blog' : 'https://www.hctestedu.com/'
}
t3 = {
'Author': '河马',
'wechat': 'ZZ777'
}
t4 = {
'Author': '河马',
'wechat': 777
}
t5 = [{
'Author': '河马',
'wechat': 'ZZ666'
}]
# Key值不同
print(DeepDiff(t1, t3).pretty())
# Key新增
print(DeepDiff(t1, t2).pretty())
# Key减少
print(DeepDiff(t2, t1).pretty())
# Key值类型改变
print(DeepDiff(t1, t4).pretty())
# 结构不同
print(DeepDiff(t1, t5).pretty())
# Key值相同
result = DeepDiff(t1, t1).pretty()
print(DeepDiff(t1, t1).pretty())
assert "" == result

输出:
Value of root['wechat'] changed from "ZZ666" to "ZZ777".
Item root['Blog'] added to dictionary.
Item root['Blog'] removed from dictionary.
Type of root['wechat'] changed from str to int and value changed from "ZZ666" to 777.
Type of root changed from dict to list and value changed from {'Author': '展昭', 'wechat': 'ZZ666'} to [{'Author': '展昭', 'wechat': 'ZZ666'}].

三、DeepSearch模块

该模支持在对象中搜索对象。

几个重要的参数:

  • use_regexp: 使用正则表达式,默认False。
  • strict_checking:强校验,默认Ture。为True时,它将检查要匹配的对象的类型,因此在搜索 '1234' 时,它将不匹配 int 1234。
  • case_sensitive:为True时,表示大小写敏感。
from deepdiff import DeepSearch
obj = ["long somewhere", "string", 0, "somewhere great!"]
# 使用正则表达式
item = "some*"
ds = DeepSearch(obj, item, use_regexp=True)
print(ds)
# 大小写敏感
item = 'someWhere'
ds = DeepSearch(obj, item, case_sensitive=True)
print(ds)
item = 'some'
ds = DeepSearch(obj, item, case_sensitive=True)
print(ds)
# 强校验
item = 0
ds = DeepSearch(obj, item, strict_checking=True)
print(ds)
item = "0"
ds = DeepSearch(obj, item, strict_checking=True)
print(ds)

输出:
{'matched_values': ['root[0]', 'root[3]']}
{}
{'matched_values': ['root[0]', 'root[3]']}
{'matched_values': ['root[2]']}
{}

正则表达式这个点的应用场景比较多,当你事先对预期结果的值不能进行100%确定时,可以使用正则匹配实际值进行断言

四、grep模块

grep是DeepSearch提供的一个更好用的方法。

它所接受的参数与DeepSearch完全相同,只是需要你用管道将对象送入它,而不是将它作为参数传递。

它的工作原理和 linux shell中的grep一样

from deepdiff import grep
obj = ["long somewhere", "string", 0, "somewhere great!"]
item = "somewhere"
ds = obj | grep(item)
print(ds)

输出:
{'matched_values': ['root[0]', 'root[3]']}

五、Extract模块

该模块可以根据值抽取其Key的路径;反过来根据Key路径提取其值

from deepdiff import extract
obj = {"a": [{'2': 'b'}, 3], "b": [4, 5]}
# root+键名+list下标+键名
path = "root[a][0]['2']"
print(extract(obj, path))

输出:
b

到此这篇关于Python全字段断言之DeepDiff模块详解的文章就介绍到这了,更多相关Python的DeepDiff模块内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 十行Python代码制作一个视频倒放神器

    十行Python代码制作一个视频倒放神器

    这篇文章主要介绍了如何通过十行代码实现视频倒放神器,轻松实现视频倒放功能。文中的示例代码简洁易懂,对我们学习Python有一定帮助,需要的可以参考一下
    2022-02-02
  • Python人工智能之波士顿房价数据分析

    Python人工智能之波士顿房价数据分析

    买房应该是大多数都会要面临的一个选择,当前经济和政策背景下,未来房价会涨还是跌?这是很多人都关心的一个话题。今天分享的这篇文章,以波士顿的房地产市场为例,根据低收入人群比例、老师学生数量等特征,利用 Python 进行分析,不求买房但求技术
    2021-11-11
  • opencv+python识别七段数码显示器的数字(数字识别)

    opencv+python识别七段数码显示器的数字(数字识别)

    本文主要介绍了opencv+python识别七段数码显示器的数字(数字识别),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Pytorch实现简单自定义网络层的方法

    Pytorch实现简单自定义网络层的方法

    这篇文章主要给大家介绍了关于Pytorch实现简单自定义网络层的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-05-05
  • django使用graphql的实例

    django使用graphql的实例

    这篇文章主要介绍了django使用graphql的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • python 划分数据集为训练集和测试集的方法

    python 划分数据集为训练集和测试集的方法

    今天小编就为大家分享一篇python 划分数据集为训练集和测试集的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • 一文带你了解Python中的生成器和迭代器

    一文带你了解Python中的生成器和迭代器

    生成器(Generators)和迭代器(Iterators)是 Python 中用于处理序列数据的强大工具,本文主要来和大家介绍一下它们的具体使用,方便大家更好的了解它们,需要的可以学习下
    2022-03-03
  • Python写一个简单的在线编辑器

    Python写一个简单的在线编辑器

    这篇文章主要介绍了如何利用Python写一个简单的在线编辑器,主要通过pywebio程序,实现了Python的简陋在线编辑器,需要的小伙伴可以参考一下,希望对你有所帮助
    2022-02-02
  • 详解tensorflow实现迁移学习实例

    详解tensorflow实现迁移学习实例

    本篇文章主要介绍了详解tensorflow实现迁移学习实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • 使用Python来开发微信功能

    使用Python来开发微信功能

    这篇文章主要介绍了使用Python来开发微信功能,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06

最新评论