深入解析Python中的JSON比较:轻松判断数据格式是否相同

前言

进行接口自动化时,有时候我们需要断言的数据比较多,一个字段一个字段进行断言比较麻烦,如果可以直接断言整个响应结果,岂不美哉,那该如何实现该功能呢?

递归

在进入正式实现前,我们先简单说一下递归。因为该功能我们主要使用递归实现,以防小伙伴们看不懂。

是什么?

递归是一种算法或函数设计方法,它通过将一个问题不断分解成规模更小的子问题来解决原始问题。在 Python 中,递归是一种函数自身调用自身的过程。通过递归,程序可以在问题空间中向下深入,并通过返回值将解决子问题的结果合并起来,最终获得整个问题的解。

如何用?

在 Python 中使用递归,首先需要定义边界条件,即递归的结束条件。当满足边界条件时,递归停止,返回结果。同时,还需要定义递归情况,即在未满足边界条件时,如何继续递归调用函数来解决子问题。递归函数应该能够将问题领域缩小,使其逐渐接近边界条件。

隐藏风险

首先,递归可能会导致堆栈溢出,特别是在处理大规模问题时。其次,递归的执行效率可能较低,因为每次递归都需要保存函数调用的上下文。此外,递归需要合理设置边界条件,否则可能导致无限循环和程序崩溃。

在编写递归函数时,需要仔细考虑边界条件和递归情况,确保递归能够正确结束,并得到期望的结果。同时,为了提高递归性能,可以考虑使用尾递归优化或迭代等技术。

案例实现

有了递归的基本了解,接下来进入正题,我们将实现如何断言整个接口响应数据。

python 复制代码
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)

代码其实也不难理解,我们做一个简单解释:

这是一个用于比较两个 JSON 数据格式是否相同的函数。每个部分的功能:

  1. 函数名称:diff_json(response_data, assert_data)

    • 参数:response_data 是接口响应数据,assert_data 是期望的断言数据。
  2. if isinstance(response_data, dict):

    • 如果 response_data 是字典类型,则进入该条件判断。

    • 循环遍历 assert_data 中的每个键(key):

      • 如果键(key)不在 response_data 中,则打印信息表示响应数据缺少该键(key)。
    • 循环遍历 response_data 中的每个键(key):

      • 如果键(key)在 assert_data 中,则递归调用 diff_json 函数进行比较。
      • 否则,打印信息表示断言数据缺少该键(key)。
  3. elif isinstance(response_data, list):

    • 如果 response_data 是列表类型,则进入该条件判断。

    • 检查响应数据和断言数据的长度是否相等,如果不相等,则打印信息表示长度不一致。

    • 如果 response_data 不为空:

      • 如果列表中的元素是字典类型,按照字典键(key)的值进行排序。
      • 如果列表中的元素不是字典类型,进行普通的排序。
    • 如果 assert_data 不为空:

      • 如果列表中的元素是字典类型,按照字典键(key)的值进行排序。
      • 如果列表中的元素不是字典类型,进行普通的排序。
    • 使用 zip 函数同时迭代 response_dataassert_data

      • 对于每个对应位置的元素,递归调用 diff_json 函数进行比较。
  4. else:

    • 如果response_data 既不是字典类型也不是列表类型,则进入该条件判断。
    • 如果 response_dataassert_data 的值不相等,则打印信息表示值不相等。

这个函数通过递归的方式,遍历并比较两个 JSON 数据结构的每一个键(key)和值。如果存在差异,将会打印出对应的信息。在需要断言和验证接口返回数据时,可以使用该函数进行检查。

好了,那我们看一看测试效果:

makefile 复制代码
response_data = {
    "name": "Alice",
    "age": 25,
    "email": "alice@example.com"
}
​
assert_data = {
    "name": "Alice",
    "email": "Alice@example.com"
}
​
diff_json(response_data, assert_data)

执行之后,会打印出如下结果:

kotlin 复制代码
Assert data has not key: age
Value are not equal: alice@example.com

完美解决!

最后

这个功能还是很实用的,大部分接口响应内容都比较复杂,想要断言的内容比较多时就比较麻烦,而这个函数可以比较两个 JSON 数据格式是否相同,节省了很多时间,提高编写接口用例的效率。

相关推荐
搜狐技术产品小编202313 分钟前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei38 分钟前
controller注册及调用时机
后端
edwarddamon1 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈1 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas1001 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
天天爱吃肉82182 小时前
【重磅发布:拿下新超仁达代理权 】
大数据·人工智能·python·功能测试·汽车
神王宝宝 王者小学2 小时前
面向领域驱动架构的查询实现方式
前端·python·架构
DantyWei2 小时前
kube-controller-manager的leader选举流程和策略
后端
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(五十四):管理员个人资料页面、管理员日志优化
前端·后端·go