阶段三-02 用例之间上下文传递

发布于:2022-07-26 ⋅ 阅读:(607) ⋅ 点赞:(0)

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() 函数用来执行一个字符串表达式,并返回表达式的值。

 Python eval() 函数 | 菜鸟教程

exec 执行储存在字符串或文件中的Python语句,相比于 eval,exec可以执行更复杂的 Python 代码。  exec obj  ;  obj -- 要执行的表达式。

Python exec 内置语句 | 菜鸟教程

上面的代码eval的时候就保存了,改成exec就能正常执行了。我们接到异常后又再抛出异常,感觉不够优雅,干脆直接报错,我们把异常交给调用它的函数来处理

参数传递

以上执行后可以发现我们 case_ctx = {}里uuid值了,那用户要怎么用?我们想要这些字段都能用上

在common里再写个方法,通过getattr循环取 redis_key , auth_username……的值,没取到就继续跑,取到了就给他应该默认的方法,方法暂时没想到

 Python getattr() 函数 | 菜鸟教程

Python setattr() 函数 | 菜鸟教程

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脚本取到验证码了,现在我们要传递验证码