关键字 开发-08 extract提取返回的结果

发布时间 2023-12-01 17:32:56作者: dack_deng

1. extract提取请求返回结果的返回值

在进行接口自动化的时候,往往需要提取上一个接口返回的值,传递给下一个接口使用。
创建utils/extract.py

import json
import re
import jsonpath
import jmespath
from utils import exceptions
from requests import Response


def extract_by_object(response: Response, extract_expression: str):
    """
    从response 对象属性取值 [status_code, url, ok, headers, cookies, text, json, encoding]
    :param response: Response Obj
    :param extract_expression:
    :return:
    """
    if not isinstance(extract_expression, str):
        return extract_expression
    res = {
        "headers": response.headers,
        "cookies": dict(response.cookies)
    }
    if extract_expression in ["status_code", "url", "ok", "encoding"]:
        return getattr(response, extract_expression)
    elif extract_expression.startswith('headers') or extract_expression.startswith('cookies'):
        return extract_by_jmespath(res, extract_expression)
    elif extract_expression.startswith('body') or extract_expression.startswith('content'):
        try:
            response_parse_dict = response.json()
            return extract_by_jmespath({'body': response_parse_dict}, extract_expression)
        except Exception as msg:
            raise exceptions.ExtractExpressionError(f'expression:<{extract_expression}>, error: {msg}')
    elif extract_expression.startswith('$.'):
        try:
            response_parse_dict = response.json()
            return extract_by_jsonpath(response_parse_dict, extract_expression)
        except Exception as msg:
            raise exceptions.ExtractExpressionError(f'expression:<{extract_expression}>, error: {msg}')
    elif '.+?' in extract_expression or '.*?' in extract_expression:
        # 正则匹配
        return extract_by_regex(response.text, extract_expression)
    else:
        # 其它非取值表达式,直接返回
        return extract_expression

def extract_by_jsonpath(extract_obj: dict, extract_expression: str):
    """
    jsonpath提取
    :param extract_obj: response.json()
    :param extract_expression: '$.code'
    :return: NONE or first value and all value
    """
    if not isinstance(extract_expression, str):
        return extract_expression
    extract_value = jsonpath.jsonpath(extract_obj, extract_expression)
    if not extract_value:
        return
    elif len(extract_value) == 1:
        return extract_value[0]
    else:
        return extract_value

def extract_by_jmespath(extract_obj: dict, extract_expression: str):
    """
    jmespath提取
    :param extract_obj: {"body": response.json(), "cookies": dict(response.cookies)}
    :param extract_expression: body.code
    :return: NONE or first value and all value
    """
    if not isinstance(extract_expression, str):
        return extract_expression
    try:
        extract_value = jmespath.search(extract_expression, extract_obj)
        return extract_value
    except Exception as msg:
        raise exceptions.ExtractExpressionError(f'expression:<{extract_expression}>, error: {msg}')

def extract_by_regex(extract_obj: str, extract_expression: str):
    """
    正则表达式提取返回结果
    :param extract_obj: must type str
    :param extract_expression:
    :return:
    """
    if not isinstance(extract_expression, str):
        return extract_expression
    extract_value = re.findall(extract_expression, extract_obj, flags=re.S)  # re.S:允许跨多行匹配
    if not extract_value:
        return ''
    elif len(extract_value) == 1:
        return extract_value[0]
    else:
        return extract_value

在用例函数中添加extract关键字提取到response返回的值:

from utils import extract
                    elif item == 'extract':
                        extract_result = {}
                        if isinstance(value, dict):
                            for extract_var, extract_expression in value.items():
                                log.info(f'提取的表达式:{extract_var}:{extract_expression}')
                                extract_var_value = extract.extract_by_object(response, extract_expression)
                                extract_result[extract_var] = extract_var_value  # 更新提取的结果,放入extract_result中
                        log.info(f'提取的结果:{extract_result}')

在.\data\test_login.yml文件中,添加extract关键字:因为我们支持三种提取方式,所以这里我写了三种,看看能不能都获取到response返回的值

config:
  name: yaml申明变量
  variables:
    username: "admin"
    password: "Admin@22"
    email1: ${email1}

test_login:
  name: 登录成功
  request:
    url: /api/v1/auth/login
    method: POST
    json:
      username: ${username}
      password: ${password}
  extract:
    code1: $.code  # 1. jsonpath方式提取code
    code2: body.code  # 2. jmespath方式提取
    token: $.data.token  
    msg: '"message":"(.*?)"'  # re正则的方式提取

终端运行:pytest .\data\test_login.yml,查看日志,可以看到成功的获取到我们的提取的参数。