context上下文,需要运用在接口执行里
参考jmeter后置处理器来设计,借用进程的内存空间来储存上下文
那么这个上下文变量放哪里呢?怎么才能做到每个用例都可以共享呢?
结合之前的代码,我们可以放在用例执的时候,没个接口执行之前。也就是common的perform_case里
admin CaseApiDef 里加两字段
per_proc = models.TextField(blank=True, null=True, verbose_name='前置处理')
post_proc = models.TextField(blank=True, null=True, verbose_name='后置处理')
定义好了要在内联表里展示
现在要用后置处理器取uuid的话用户需要写一下python脚本
#{case_ctx['uuid'] = parse(reslut['text'])['uuid']}
加上后置处理并传入case_ctx,顺便用日志记录下。这样用户才能去调用 case_ctx['uuid']
我们再抄下之前python表达式校验的代码改一下就可以用了,之后我们再考虑提取复用的问题。
common里重新写一个:
def eval_expression(input_, result, case_ctx): # 仅先实现后置处理 TODO
if not input_:
return
m = re.match(r"#\{.+\}", input_)
if not m:
raise Exception(f'内容格式不支持,请使用#{{}}包含[{input_}]')
exp = m.group()
if re.search(r"__.+__", input_): # __import__.os 等被过滤掉
raise Exception(f'python表达式包含非法字符或操作')
# 约定可提供的数据 result
local_params = {
'result': result,
're': re,
'parse': common.parse_json_like,
'case_ctx': case_ctx,
}
try:
# 执行eval
eval(exp[2:-1], {}, local_params) # eval执行后会返回一个布尔值,[2:-1]做个切片去掉用户输入的#{}
# 可以不要返回值 所以不用 if not eval_:
except Exception as e:
raise Exception(f'表达式执行失败,请先修正后再执行用例。参考【{e}】')
去运行用例,此时会报错
断点看下用户输入的我们取道了,但是没写入。上面代码最后一行加上,
trace_msg = traceback.format_exc() 抛出详细信息再看看
排除后发现我们在执行用户给的代码时出错了。。。
eval和exec
eval() 函数用来执行一个字符串表达式,并返回表达式的值。
exec 执行储存在字符串或文件中的Python语句,相比于 eval,exec可以执行更复杂的 Python 代码。 exec obj ; obj -- 要执行的表达式。
上面的代码eval的时候就保存了,改成exec就能正常执行了。我们接到异常后又再抛出异常,感觉不够优雅,干脆直接报错,我们把异常交给调用它的函数来处理
参数传递
以上执行后可以发现我们 case_ctx = {}里uuid值了,那用户要怎么用?我们想要这些字段都能用上
在common里再写个方法,通过getattr循环取 redis_key , auth_username……的值,没取到就继续跑,取到了就给他应该默认的方法,方法暂时没想到
def proc_apidef_params(item: CaseApiDef, case_ctx):
for attr in ['redis_key', 'auth_username', 'auth_password', 'bearer_token']:
val = getattr(item, attr)
if not val:
continue
setattr(item, attr, '??')
接下来写??位置的函数:
把用户输入的val校验里面包含#{}的排除掉,如果排除后里面是0就直接返回它本身并结束。
local_params是给用户调用的
re.sub()是把 #{}里的替换成 new_content ,从用户输入的val里找
new_content ()里matched 是前面 re.sub里r"#\{.+\}"匹配到的:<re.Match object; span=(0, 19), match="#{case_ctx['uuid']}"> 我们 让 s=matched.group() 就可以取全部组了,值就是 #{case_ctx['uuid']}
def proc_params_expression(val, case_ctx):
ms = re.findall(r"#\{.+\}", val)
if len(ms) == 0:
return val
local_params = {
'case_ctx': case_ctx,
're': re,
'parse': common.parse_json_like
}
def new_content(matched):
s = matched.group()
if re.search(r"__.+__", s): # __import__.os 等被过滤掉
raise Exception(f'python表达式包含非法字符或操作[{s}]')
return eval(s[2:-1], {}, local_params)
return re.sub(r"#\{.+\}", new_content, val)
校验是不是数字
以上就可以通过用户写的python脚本取到验证码了,现在我们要传递验证码