目录

如何在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性能测试

九、总结(尾部小惊喜)

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

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

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

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

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

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
love530love6 分钟前
记一次不太顺利的Docker重装
运维·docker·容器
刘若水12 分钟前
Linux: 系统内核中的信号
linux·运维·服务器
孙同学_1 小时前
【Linux篇】基础IO - 文件描述符的引入
linux·运维·网络
张彦峰ZYF2 小时前
高频面试题(含笔试高频算法整理)基本总结回顾63
linux·运维·算法
从零开始学习人工智能4 小时前
Docker 镜像导出与导入:export/import vs save/load
运维·docker·容器
rufeike8 小时前
Rclone同步Linux数据到google云盘
linux·运维·服务器
csdn_aspnet8 小时前
如何在 Linux 上安装 Python
linux·运维·python
西贝爷10 小时前
批量删除git本地分支和远程分支命令
运维
珊瑚里的鱼10 小时前
第五讲(下)| string类的模拟实现
开发语言·c++·笔记·程序人生·算法·visualstudio·visual studio
jianbiao148310 小时前
远程服务器下载llama模型
运维·服务器