场景:
httprunner(1.5.8) 在引用函数时,
1、如果入参是字符串,引用时不能使用单双引号
${func(var1="xxx")}
2、如果入参是日期格式,%号也无法使用
${get_year(fmt="%Y")}
3、如果入参是列表元组字典等,如a=[1,2],b=(1,),c={'a':1, 'b':2}
$func(a=[1,2],b=(1,),c={'a':1, 'b':2})
上面三个函数引用无法生效,httprunner没有解析到函数。
问题分析:
httprunner在运行用例时,调用TestcaseLoader(testcase.py)来解析用例。解析函数时,主要有四步
1、extract_functions(39行)提取函数字串,如下
应用的正则表达式:function_regexp = r"\$\{([\w_]+\([\$\w\.\-_ =,]*\))\}"
(18行)
返回函数字串列表${func(5)} => ["func(5)"]
从上图对正则的分析,可看到,原正则是不支持带{}、[]、()、%、:等符号的,相当于直接限制了引用函数时参数的数据类型。后面的改造也要从这开始着手。
2、parse_function(70行)二次解析函数字串,处理把上面获取的内容(“func(5)”)
应用的正则表达式:function_regexp_compile = re.compile(r"^([\w_]+)\(([\$\w\.\-_ =,]*)\)$")
(19行)
上面的表达式把函数调用字串提取成两部分:函数名和入参字串
提取结果就是[('func', '5')]
注意:此表达式也缺少匹配{}、[]、()、%、:等符号,也要改造
3、整合参数:
原代码:
从原代码可以看出,对参数列表的处理是直接使用逗号分割(99行)
如果参数列表是下面这种情况,是可以正常解析的
func(1,2,a=3,b=4)
最后会返回数据如下:
function_meta = {
"func_name":"func",
"args":[1,2],
"kwargs": {'a':3,'b':4}
}
但如果是带列表、元组、字典、集合等类型数据时,按这种简单的逻辑是无法处理的({’a':1,'b':2}
完整字典被错误分割了)。
这段代码要改造,能够正确的解析出如下面情况的参数字串
$name, 1,2,[1,2],(1,), a=(1,), b=True, c=[1,2], d={'a':1,'b':2}
4、再从当前环境绑定的函数中获取函数对象,并执行并返回结果
从上面流程看,正则匹配失败和参数字串解析是问题的根因,下面是调试可行的完整代码。
源码修改(文件testcase.py):
第一步:
原代码:function_regexp = r"\$\{([\w_]+\([\$\w\.\-_ =,]*\))\}"
原来对参数字串匹配的部分\([\$\w\.\-_ =,]*\)
直接修改为放开限制\(.*?\)
,使用非贪婪方式不限制字符来匹配中括号里的参数字串
修改后的完整表达式function_regexp = r"\$\{([\w_]+\s*\(.*?\))\}"
第二步:
原代码:function_regexp_compile = re.compile(r"^([\w_]+)\(([\$\w\.\-_ =,]*)\)$")
修改后:function_regexp_compile = re.compile(r"^([\w_]+)\s*\((.*?)\)$")
第三步:
解析参数字串(函数parse_function)
参数字串的完整正则表达式:r=r"""(?:(\w+?)\s*?=\s*?)?(\w+\.\w+|\".*?\"|\'.*?\'|\{.*?\}|\(.*?\)|\[.*?\]|\d+\.?\d+|\d|\w+|\$\w+)"""
【已更正 20190920】
到此,基本上代码就算改造完成了。
下面就可以按python的习惯来调用函数,写参数了。基本上能适配大多数情况了。
但还有种情况没有适配:testfunc(*[77,88],**{‘a’:1,‘b’:2})。不过没关系了,把列表和字典拆包就行了。
运行结果: