接口自动化测试,一键快速校验接口返回值全部字段

简介: 在日常开展自动化测试工作时,为了保证接口测试的有效性,少不了要对接口返回的响应字段进行校验、断言等操作。当接口返回的字段数量本身就很少时,接口断言操作一般都很容易就能实现,但当接口的返回字段特别多,结构特别复杂时,例如响应字段数量达到了成百上千时,如何快速实现全部返回字段的校验?

大家好,我是狂师。

在日常开展自动化测试工作时,为了保证接口测试的有效性,少不了要对接口返回的响应字段进行校验断言等操作。当接口返回的字段数量本身就很少时,接口断言操作一般都很容易就能实现,但当接口的返回字段特别多,结构特别复杂时,例如响应字段数量达到了成百上千时,如何快速实现全部返回字段的校验?这类问题,相信困扰了很多的正在开展接口测试的小伙伴。

今天针对如何快速审核接口返回值全部字段问题,分享一些解答思路,希望能帮到大家~

其实解决上述之类问题,市面上常见的解决方案有两类:

  • 根据业务校验需求,自定义开发校验规则库
  • 借助现有的第三方库

今天,我们先来聊聊,如何借助现有的第三方库来解决: 快速校验API接口返回的全部字段。由于当今大部分接口都是基于Restful API,后续我介绍中,我们假设接口响应体格式以JSON为例。

要满足上面的实现需求,第三方库方案有很多,比如常见的就有:deepdiffdifflibjson-diffjson_tools 等,这些三方库之间,都有各自侧重点,本篇文章,重点介绍:如何借助DeepDiff库来解决快速校验接口返回字段的问题

一、认识一下,DeepDiff 介绍


Deepdiff模块常用来校验两个对象是否一致,并找出其中差异之处。其中提供了三个类,DeepDiff,DeepSearch和DeepHash,官网地址:https://deepdiff.readthedocs.io/en/latest/ ,当前最新版本为:V5.5.0

微信图片_20220526234341.png

主要组成部分:

  • DeepDiff:比较两个对象,对象可以是字段、字符串等可迭代的对象,针对对象的深层差异,递归查找所有更改。
  • DeepSearch:在对象中搜索其他对象
  • DeepHash:根据对象的内容进行哈希处理

DeepDiff 的初衷是用来找出不同数据的差别,可以比较JSONXML文本类的,也可以比较图片,在使用了一下之后,其实我们完全可以直接使用它作为测试的断言,这也是从另一个思考角度提供了一种全新的校验思路

二、DeepDiff 使用


当你看完上述的介绍,相信还是一脸懵,不知如何下手,接下来,就通过几个案例来进一步感受一下Deepdiff的功能和作用。

使用之前,先安装:

pip install deepdiff

2.1 案例一:比较两个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 差异的输出结果是:

.{'dictionary_item_added': [root['timestamp']],
 'dictionary_item_removed': [root['code']],
 'values_changed': {"root['Object']['message']": {'new_value': 'failure',
                                                  'old_value': 'success'}}}

上述输出结果中,实际上根据这个返回的 json 获取所有的差别。主要是对比对象之间的值、类型前后之间的变化以及删除的或者增加的情况key进行了结果输出。

主要包含以下四种情况:

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

2.2 案例二:比较接口响应


有了案例一的基础,进一步,我们将本地定义写死的变量值改成采取调用接口的方式(更符合实际接口测试),通过发起请求,获取响应、并结合Deepdiff来断言使用。

核心思路:先定义预期的响应结构体(意味着,你得事先知道你期望的结果是什么),再根据实际返回的结构体两者通过Deepdiff进行自动比较。

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))

由于实际返回的结构体和预期定义待校验的结构体数据完全一样,因此上述代码输出结果为:{},即两者没有差异。(也意味着实际和预期结果一致)

在此基础上,如果我们把上述expected_reps预期结构体中的authorYours Truly修改为Yours,再执行一次,则输出的结果为:

{'values_changed': {"root['slideshow']['author']": {'new_value': 'Yours Truly',
                                                    'old_value': 'Yours'}}}

从上述的输出结果中,我们可以很明显的获取到三个讯息:

  • 接口返回的结构体中有值发生了改变,通过values_changed标识出来了
  • 明确指出具体哪个字段的值发生改变了,如root['slideshow']['author']
  • 改变具体的内容,如实际返回值为Yours Truly,而预期值为Yours

看完了这个,相信此时的你,对Deepdiff在接口测试中的使用,已经有了一些感觉了。但接着你肯定会提出疑问,有些接口返回的值,并不是固定的,那比如校验呢。比如某个时间戳字段,每次调用接口时,返回字段的值都是不一样,针对这类只知道数据规则,但数据本身的值一开始是无法确定的,又该如何结合Deepdiff来使用呢?别急,再接着往下看。

2.3 案例三:正则搜索匹配

要解决上述的问题,可以利用DeepSearch中的正则搜索匹配功能,如果你的接口返回,是一个很深的嵌套结构对象,然后你想校验查找指定的元素(key和value都行)是否存在,那么Deep Search将是个好选择。

使用前,需要先导入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)

比如想校验有没有以mike开头字段或值在返回的结构体中,指定元素存在则返回它的路径;不存在则返回一个空字典。上述输出结果如下:

.{'matched_paths': ["root['mikezhou']"], 'matched_values': ["root['info']['author']['tag']"]}

上述示例虽简单,但如果你足够聪明,相信应该已经能从中Get核心思路了:针对一些动态事先无法预料的值,可以通过借助正则表达式来匹配校验,具体如何校验,取决于你的正则表达式如何描述。

三、小技巧:DeepDiff 黑名单


在实际做接口测试断言时,有时对象顺序不一样,但是实际情况两个值还是一样的,或者是针对全量字段校验时,想跳过一些特殊的字段校验(类似黑名单一样,将不需要校验的字段,明确指出),为了解决这类问题,Deepdiff也提供了相信的参数,只需要在比较的时候加入:

  • ignore order(忽略排序)
  • ignore string case(忽略大小写)
  • exclude_paths字段黑名单排除参数即可,原型如下:
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']"}))

上述示例代码,忽略了排序规则、大小写问题,并且指定排除timestamp字段校验。具体的输出结果如下:

{'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'}}}

四、小结


通过上述的案例介绍,相信你对DeepDiff的使用有了一个基本认识。在接口自动化测试中,小结一下,使用 DeepDiff 的好处有:

  1. 接口测试的时候,可以直接利用预期结构体(或者称之为接口契约)与实际返回的结构体(字段、值)进行自动比较,来确定是不是一样,可以少写很多代码。
  2. 数据库数据比较的时候也是一样可以,使用 SQL查出结果之后,直接变成 JSON就可以和期望的 JSON对比了。

本文旨在从另一个视角帮大家提供一些接口测试全量字段校验的解决思路,更多关于Deepdiff使用技巧,以及更优解的全量字段解决方案(还有很多),欢迎大家积极探索。

目录
相关文章
|
8天前
|
安全 前端开发 测试技术
如何选择合适的自动化安全测试工具
选择合适的自动化安全测试工具需考虑多个因素,包括项目需求、测试目标、系统类型和技术栈,工具的功能特性、市场评价、成本和许可,以及集成性、误报率、社区支持、易用性和安全性。综合评估这些因素,可确保所选工具满足项目需求和团队能力。
|
8天前
|
机器学习/深度学习 SQL 安全
如何确保自动化安全测试的全面性和准确性?
如何确保自动化安全测试的全面性和准确性?
|
9天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
38 3
|
1月前
|
测试技术
自动化测试项目实战笔记(三):测试用户注册(验证码错误,成功,出现弹框时处理)
本文是关于自动化测试项目实战笔记,主要介绍了如何测试用户注册功能,包括验证码错误、注册成功以及弹框处理的测试步骤和代码实现。
87 2
自动化测试项目实战笔记(三):测试用户注册(验证码错误,成功,出现弹框时处理)
|
1月前
|
测试技术
自动化测试项目学习笔记(五):Pytest结合allure生成测试报告以及重构项目
本文介绍了如何使用Pytest和Allure生成自动化测试报告。通过安装allure-pytest和配置环境,可以生成包含用例描述、步骤、等级等详细信息的美观报告。文章还提供了代码示例和运行指南,以及重构项目时的注意事项。
177 1
自动化测试项目学习笔记(五):Pytest结合allure生成测试报告以及重构项目
|
1月前
|
测试技术 Python
自动化测试项目学习笔记(一):unittest简单运行(初始化,清除,设置测试行为)
本文介绍了Python的unittest框架的基础用法,包括测试初始化(setup)、清除(tearDown)函数的使用,以及assertEqual和assertGreaterEqual等断言方法,并展示了如何创建测试用例,强调了测试函数需以test_开头才能被运行。
63 1
自动化测试项目学习笔记(一):unittest简单运行(初始化,清除,设置测试行为)
|
18天前
|
前端开发 数据管理 测试技术
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第27天】本文介绍了前端自动化测试中Jest和Cypress的实战应用与最佳实践。Jest适合React应用的单元测试和快照测试,Cypress则擅长端到端测试,模拟用户交互。通过结合使用这两种工具,可以有效提升代码质量和开发效率。最佳实践包括单元测试与集成测试结合、快照测试、并行执行、代码覆盖率分析、测试环境管理和测试数据管理。
35 2
|
19天前
|
前端开发 JavaScript 数据可视化
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第26天】前端自动化测试在现代软件开发中至关重要,Jest和Cypress分别是单元测试和端到端测试的流行工具。本文通过解答一系列问题,介绍Jest与Cypress的实战应用与最佳实践,帮助开发者提高测试效率和代码质量。
28 2
|
13天前
|
Web App开发 测试技术 数据安全/隐私保护
自动化测试的魔法:使用Python进行Web应用测试
【10月更文挑战第32天】本文将带你走进自动化测试的世界,通过Python和Selenium库的力量,展示如何轻松对Web应用进行自动化测试。我们将一起探索编写简单而强大的测试脚本的秘诀,并理解如何利用这些脚本来确保我们的软件质量。无论你是测试新手还是希望提升自动化测试技能的开发者,这篇文章都将为你打开一扇门,让你看到自动化测试不仅可行,而且充满乐趣。
|
1月前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
59 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)