我们的接口自动化框架的测试数据放到json文件中,
但是有些参数是动态生成的(例如随机字符串);有些参数可以进行再次提取,放在config文件里(例如host,URL,accountid等等);
解决这个问题我想到两个解决方法:
1,在测试case的python文件中生成变量后再赋值给json文件中的变量(缺点:重复代码多)
2,在json文件中直接引用函数 or 变量名称,在case读取json文件时,替换变量(此文重点介绍这种方法)
进入正题,第一步:替换变量。
首先介绍一下我的测试数据是放在json文件里的,形式如下;比如像host,uri,account_id 是需要替换的
"test": [
{
"tag":"test render string",
"case": "测试如何替换测试参数",
"http": {
"host": "1",
"uri": "1",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"params": {
"region": "cn",
"lang": "zh-cn",
"app_id": "10001",
"nonce": "${generate_random_digits()}"
},
"data": {
"account_id": "{user.owner.account_id}"
"mobile":"{user.owner.mobile}"
}
},
"expected": {
"response": {
"result_code": "success",
},
"database": {},
"kafka": {}
}}
]
}
第二步:
我们把例如account_id这种数据放在config文件夹下,可以存放为yaml活着json都可以;只要读取数据出来的形式是字典就行
cache = {
"VARIABLES":{
"user":{
"owner":{
"account_id":"test123",
"mobile": "13677777777"
}
}}
}
至此,需要替换的数据是第一步读取的;要替换的target数据是第二步读取的
第三步:编写render函数进行数据替换,这里替换的是变量
import logging
import re
p = '''{
"test": [
{
"tag":"test render string",
"case": "测试如何替换测试参数",
"http": {
"host": "1",
"uri": "1",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"params": {
"region": "cn",
"lang": "zh-cn",
"app_id": "10001",
"nonce": "${generate_random_digits()}"
},
"data": {
"account_id": "{user.owner.account_id}"
"mobile":"{user.owner.mobile}"
}
},
"expected": {
"response": {
"result_code": "success",
},
"database": {},
"kafka": {}
}}
]
}'''
cache = {
"VARIABLES":{
"user":{
"owner":{
"account_id":"1559759948",
"mobile": "98762424749"
}
}}
}
varial_matcher = re.compile(
r"\{([\w.]+)\}"
r"|\$\{([\w.]+)\}" # 匹配$开头并{}包括的变量
)
def render(p, cache):
# 替换变量
if isinstance(p, str) and varial_matcher.findall(p):
variables_list = []
try:
for var_tuple in varial_matcher.findall(p):
variables_list.append(
var_tuple[0] or var_tuple[1]
)
for items in variables_list:
items_list = items.split('.')
target_data = cache.get("VARIABLES")
for i in items_list:
target_data = target_data.get(i, {})
if target_data != {}:
p = p.replace('${', '{').replace("{" + items + "}", str(target_data))
return p
except Exception as e:
logging.error(e)
logging.error(p)
print(render(p, cache))
第四步:在测试数据的json文件中还有这种
"nonce": "${generate_random_digits(2)}"
引用函数的,需要替换成引用函数后的结果;怎么做呢?和步骤三大同小异
func_matcher = re.compile(
r"[\$]{1}[\{]{1}" # 可以匹配${}的函数
r"([0-9a-zA-Z_.=]+)" # 匹配函数名称可以包含.
r"[ ]*" # 函数方法名称后0或多个空格
r"\((.*)\)" # 匹配函数参数
)
def render(p, cache):
# 替换函数
if isinstance(p, str) and func_matcher.findall(p):
for fn_tuple in func_matcher.findall(p):
fun, varials = fn_tuple[0], fn_tuple[1]
fnc_map = cache.get("FUNCS")
try:
fn_raw = "{fun}({varials})".format(fun=fun, varials=varials)
fn = "{fun}({varials})".format(fun=fun, varials=varials)
target_data = eval(fn, fnc_map)
p = p.replace('${', '{').replace("{" + fn_raw + "}", str(target_data))
except (ModuleNotFoundError, ImportError) as e:
logging.warning("函数没找到或者导入失败", p, cache)
except NameError as e:
logging.warning("err", e)
return p
print(render(p, cache))
但是在这步前要再自行加一步,就是在cache的数据中,加入我们写好的FUNC参数,以及我们需要替换的函数文件
比如 我的替换函数文件:
#我的func_tools文件
def generate_random_digits(num):
return str(round(random.uniform(-90, 90), num))
就是在cache的数据中,加入我们写好的FUNC参数
cache["FUNCS"] = load_func_tools("func_tools")
def load_func_tools(module):
try:
module_functions = {}
module = import_module(module)
if module:
for name, item in vars(module).items():
if isinstance(item, types.FunctionType):
module_functions[name] = item
return module_functions
except Exception:
return {}