前言
测试工作中往往需要对服务端所返回的Json数据做容错,即需要确保原数据中各项值被替换成异常数据类型时,相关数据传输与处理系统不会发生报错、崩溃等问题。
若手动编写容错数据,小编认为有以下两点弊端:
1. 繁琐操作带来的人力、时间成本消耗;
2. 可能因数据繁多而导致疏漏;
因此希望实现能够根据待测试Json数据,一键输出全部相关容错数据文件的脚本。
概述
开始代码实现之前希望能够明确思路,小编经过思考,确立脚本实现环节如下:
1. 获取key
获取Json中所有需做数据替换处理的元素标识(如Json对象中的各个key);
2. 定位value
根据获取到的标识,定位到需修改的值(如key对应的value);
3. 替换与输出
将每个值进行数据替换并输出为各式容错数据文件。
实现方案
1. 获取key
以这样一份基本包含各式数据的Json为例
{
"testDict":{
"testDict_1_string":"1_value",
"testDict_2_int":1,
"testDict_3_bollen":false,
"testDict_4_list":["4_value",1],
"testDict_5_null":null,
"testDict_6_dict":{"6_key":{"6_key_1":"6_value_1"}, "6_list":["test_list"]},
"testDict_7_complex":[
{
"id":"10000",
"testA":{"A":"A_value"},
"testB":["B1","B2"]
},
{
"id":"10001",
"testC":{"C":"C_value"},
"testRepeat":"R_value"
},
["testX", "testY", {"testRepeat":"testRepeat"}],
["test_list_2"],
"7_value"
],
"testRepeat":"R_value"
},
"testRepeat":"R_value",
"test_extra":["test_extra_value"]
}
小编尝试通过对其进行递归处理进行key的获取,并辅以这样几点思考:
1. 针对数据中字典形式的json对象、列表形式的json数组,需不同的处理方法;
2. 为避免重复key混淆,需使用数据链路结构进行区分,如“父级key—子级key—子级key”;
3. 为避免链路结构同key产生混淆,需使用特殊符号进行层级链接。
4. 为避免多重数组导致数据链路结构重复,需额外添加”inlist”标识。
代码如下:
def getKeyFromJsonFile(dic_json, keylist, keyParent=None, isChild=False, listInlist=False):
# 如果获取到的数据类型为dict,则遍历字典的key来获取value数据类型
if isinstance(dic_json, dict):
for key in dic_json:
# 根据value数据类型做不同处理并递归
if isinstance(dic_json[key], dict):
# 拼接节点路径并插入列表
if isChild:
key = keyParent + '-*-' + key
keylist.append(key)
getKeyFromJsonFile(dic_json[key.split('-*-')[-1]], keylist, keyParent=key, isChild=True, listInlist=False)
elif isinstance(dic_json[key], list):
if isChild:
key = keyParent + '-*-' + key
keylist.append(key)
for i in dic_json[key.split('-*-')[-1]]:
getKeyFromJsonFile(i, keylist, keyParent=key, isChild=True, listInlist=False)
else:
# 列表内的key可能和列表内列表的key结构重复
# 仅处理一层,再深层缺乏实际意义
if listInlist:
key = key + '_*inlist'
if isChild:
key = keyParent + '-*-' + key
keylist.append(key)
# 针对[...]中包含[...]需再次递归
if isChild and isinstance(dic_json, list):
for i in dic_json:
getKeyFromJsonFile(i, keylist, keyParent=keyParent, isChild=True, listInlist=Tru
2. 定位value
小编尝试将每个key值以链接符号-*-进行分割为列表,并于Json数据中逐级进行找寻、定位,此时对这样两种情况进行了考虑。
若key值对应的value类型并非列表,则位于链路末端的key值对应的value即是需要修改的值:
def getValue(slist, data_next):
# 遍历分割后的key参数
for j in range(0 ,len(slist)):
# 当前key对应的数据类型是list
if isinstance(data_next[slist[j]], list):
return
# 并非列表
if j == len(slist)-1:
# 得到需要修改的值
value = data_next[slist[j]]
return
# 每次节点路径的循环中在下一级字典中检索
data_next = data_next[slist[j]]
而列表内元素无法根据key值定位,直接定位到列表后续进行遍历即可:
def getValueFromList(data_list, key_list):
# 列表中元素数据类型为字典
if isinstance(data_list, dict):
for key in key_list:
# 在字典中由传入的key进行检索
if key in data_list.keys() and key == key_list[-1]:
# 得到需要修改的值
value = data_list[key]
# 如果dict内部仍有list
if isinstance(data_list[key], list):
# 得到需要遍历其内元素进行修改的目标列表
value = data_list[key]
return
# 有子节点则继续递归
elif key in data_list.keys():
getValueFromList(data_list[key], key_list)
二者结合,则getValue方法内列表相关逻辑应是:
if isinstance(data_next[slist[j]], list):
# 当前key无子节点
if j == len(slist)-1:
# 得到需要遍历其内元素进行修改的目标列表
value = data_next[slist[j]]
# 截取后续子节点在列表中进行递归
else:
for datas in data_next[slist[j]]:
tlist = slist[j+1:]
getValueFromList(datas, tlist)
return
1. 针对列表中包含列表,需添加判断isinstance(data_list, list)继续递归处理;
2. 针对添加了inlist的列表标识,需进行字符串分割后再去遍历取值。
3. 替换与输出
通过遍历预设的测试数据列表即可对需要修改的值进行替换,列表示例如下:
# Json容错常用数据类型
null = None
false = False
type_list = ["testString", 1, false, null, ["test_list"], {"test_dict":"test_dict_v
修改后的数据指向的仍是原待测试Json数据(需要在每次修改、输出文件后进行数据还原),直接将其写入文件即可——将以容错类型命名的每组数据存入以数据链路key值命名创建的文件夹内(避免输出相同结构的重复数据):
# path为预设好的文件夹路径+文件名称
with open(path, "w") as f:
json.dump(data, f, sort_keys=True, indent=4, ensure_ascii=False)
此外,缺省(如Json数据中不存在这一key)同样是一种常规的数据容错方式,可使用pop()方法操作字典、列表对相应值进行删除予以实现。
运行结果
综上,运行脚本可得容错文件如图——针对需要替换的值,每组容错数据包含int、string、bool等数据类型及数据缺省:
打开任一文件,如图中...-testA-*-A_int.json,可见原数据中相应值已被替换成了预设值:
// Json中相应位置
"testDict_7_complex": [
{
"id": "10000",
"testA": {
"A": 1
},
至此,一键自动化输出Json容错数据文件的目的便达成了。感谢阅读,欢迎交流。
python测试应用系列其他文章: