如何在pytest接口自动化框架中扩展JSON数据解析功能?

开篇

上期内容简单说到了。params类类型参数的解析方法。相较于简单。本期内容就json格式的数据解析,来进行阐述。

在MeterSphere中,有两种方式可以进行json格式的数据维护。一种是使用他们自带的JsonSchema来填写key-value表单。另一种就是手写json。

手写json在日常工作中效率较低,原因有二,一是手写太麻烦,占据大量个工作时间,影响效率。二是对正确性以及层级结构无法保证准确性。两者相比较,故选择JsonSchema的方式来维护json格式的数据。

json格式数据模型如下

python 复制代码
"jsonSchema": {
      "properties": {
        "字段1": {
          "mock": {
            "mock": ""
          },
          "type": "string",
          "description": "字段描述。。。"
        },
        "字段2": {
          "type": "number",
          "mock": {
            "mock": ""
          },
          "minLength":50,
          "maxLength":100
        },
        "字段3": {
          "type": "integer",
          "mock": {
            "mock": ""
          },
          "description": "字段描述"
        }
      },
      "type": "object",
      "mock": {
        "mock": ""
      },
      "required": [
        "字段1",
        "字段2",
      ]
    }

使用JsonSchema作为最外层节点,第二层节点包含了类型、字段属性、必填字段列表等参数信息。第三层节点就是字段的一些属性,包含了字段长度、字段名称、字段类型、字段描述等

特别需要说明的是,MeterSphere的字段类型有很多,其中包含了object以及array这两种类型的数据

object:如果字段类型是object,那么该字段节点下会嵌套另外一些字段,这些字段也是json格式的

array:同理,如果字段类型是array,那么该字段下面会嵌套一个列表,列表中的每一个元素,都是json格式,不可以手动设置key,是从0递增自动命名。

这两种类型是可以无限重复套娃下去。只要你需要。

所以在解析这类数据时,我们就需要先解决这种层层嵌套的问题。

思路梳理

首先判断一下数据类型是否为上述这种套娃格式

判断字段类型是object还是array

利用python的递归,调用自身。并将字段属性作为参数传给这个函数

然后提取字段中的最大值,最小值,以及参数名称、类型

判断当前字段是否在必填列表中,如果在,则将这个字段设置为必填

如上是大概的解题思路,抛开拆解套娃,代码相对简单。如下是源码展示

python 复制代码
# 解析json请求的参数
def post_arguments(data, required_list=None):
    field = {}
    if not isinstance(data, dict):
        raise TypeError("'data' is not dict")
    for key, value in data.items():
        if value["type"] == "object" and "properties" in value:
            # 递归调用,实现多层嵌套解析
            if "required" in value:
                recursion_par = post_arguments(value["properties"], value["required"])
                par = {
                    key:
                        {"type": value["type"],
                         "description": value["description"] if "description" in value else "",
                         **recursion_par
                         }
                }
                field.update(par)
            else:
                recursion_par = post_arguments(value["properties"])
                par = {
                    key: {"type": value["type"],
                          "description": value["description"] if "description" in value else "",
                          **recursion_par
                          }
                }
                field.update(par)
        elif value["type"] == "array" and "items" in value:
            for l, i in enumerate(value["items"]):
                for arr_key, arr_value in i.items():
                    if arr_value == "object" and "properties" in arr_value:
                        # 递归调用,实现多层嵌套解析
                        if "required" in arr_value:
                            recursion_par = post_arguments(arr_value["properties"], value["required"])
                            par = {
                                l: {"type": value["type"],
                                    "description": value["description"] if "description" in value else "",
                                    **recursion_par
 
                                    }
                            }
                            field.update(par)
                        else:
                            recursion_par = post_arguments(arr_value["properties"])
                            par = {
                                l: {"type": value["type"],
                                    "description": value["description"] if "description" in value else "",
                                    **recursion_par
                                    }
                            }
                            field.update(par)
                    elif arr_value == "array" and "items" in arr_value:
                        if "required" in arr_value:
                            recursion_par = post_arguments(arr_value["properties"], arr_value["required"])
                            par = {
                                l: {"type": value["type"],
                                    "description": value["description"] if "description" in value else "",
                                    **recursion_par
                                    }
                            }
                            field.update(par)
                        else:
                            recursion_par = post_arguments(arr_value["properties"])
                            par = {
                                l: {"type": value["type"],
                                    "description": value["description"] if "description" in value else "",
                                    **recursion_par
                                    }
                            }
                            field.update(par)
                    else:
                        maxLength = MAX_LENGTH
                        minLength = MIN_LENGTH
                        required = "false"
                        if "maxLength" in arr_key:
                            maxLength = i["maxLength"]
                        elif "maxLength" in arr_key:
                            minLength = i["minLength"]
                        if required_list:
                            if l in required_list:
                                required = "true"
                        items_par = {
                            key:
                                {
                                    "type": value["type"],
                                    "description": value["description"] if "description" in value else "",
                                    l: {
                                        "type": i["type"],
                                        "required": required,
                                        "max": maxLength,
                                        "min": minLength
                                    }
                                }
                        }
                        field.update(items_par)
        else:
            maxLength = MAX_LENGTH
            minLength = MIN_LENGTH
            required = "false"
            if "maxLength" in value:
                maxLength = value["maxLength"]
            elif "minLength" in value:
                minLength = value["minLength"]
            if required_list:
                if key in required_list:
                    required = "true"
                else:
                    required = "false"
            par = {
                key: {
                    "type": value["type"],
                    "description": value["description"] if "description" in value else "",
                    "required": required,
                    "max": maxLength,
                    "min": minLength,
                }
            }
            field.update(par)
    return field
 

可以看到,思路不是很难,但是代码还是比较臃肿的,其中有很多的代码是冗余的,在后期优化中,将考虑这块重构一下。大家在写的时候将思路缕清,别写出我这么烂的代码。。。。引以为戒~

结语

总结一下这个函数

首先在写的时候,多重嵌套是个难题,可以通过递归的方式解决

另外一定在思路缕清的前提下,再开始写代码,我就是在边写边思考,一个for循环一个for循环的嵌套。导致代码极其臃肿。执行效率有一定程度的降低,且代码可读性不好

公共代码提取:像一些数据结构模板,这些都可以提取成一个公共变量,然后调用即可。在函数中反复写着相类似的模板,是一种很愚蠢的行为。。。


【下面是我整理的2023年最全的软件测试工程师学习知识架构体系图】


一、Python编程入门到精通

二、接口自动化项目实战

三、Web自动化项目实战

四、App自动化项目实战

五、一线大厂简历

六、测试开发DevOps体系

七、常用自动化测试工具

八、JMeter性能测试

九、总结(尾部小惊喜)

生命不息,奋斗不止。每一份努力都不会被辜负,只要坚持不懈,终究会有回报。珍惜时间,追求梦想。不忘初心,砥砺前行。你的未来,由你掌握!

生命短暂,时间宝贵,我们无法预知未来会发生什么,但我们可以掌握当下。珍惜每一天,努力奋斗,让自己变得更加强大和优秀。坚定信念,执着追求,成功终将属于你!

只有不断地挑战自己,才能不断地超越自己。坚持追求梦想,勇敢前行,你就会发现奋斗的过程是如此美好而值得。相信自己,你一定可以做到!

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

相关推荐
梁诚斌2 分钟前
VSOMEIP代码阅读整理(1) - 网卡状态监听
运维·服务器·网络
深情废杨杨23 分钟前
服务器几核几G几M是什么意思?如何选择?
运维·服务器
康熙38bdc24 分钟前
Linux 进程优先级
linux·运维·服务器
Web极客码25 分钟前
常见的VPS或者独立服务器的控制面板推荐
运维·服务器·控制面板
只是有点小怂29 分钟前
parted是 Linux 系统中用于管理磁盘分区的命令行工具
linux·运维·服务器
三枪一个麻辣烫1 小时前
linux基础命令
linux·运维·服务器
cuisidong19971 小时前
如何在 Kali Linux 上安装 Google Chrome 浏览器
linux·运维·chrome
___Dream2 小时前
【黑马软件测试三】web功能测试、抓包
前端·功能测试
wusam2 小时前
螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习03(网络及IP规划)
运维·服务器·网络·docker·容器
南种北李2 小时前
Linux自动化构建工具Make/Makefile
linux·运维·自动化