Python pytest+yaml 文件,怎么在 yaml 文件中引用变量?

Sdw · 2023年03月10日 · 最后由 tester 回复于 2023年03月20日 · 8601 次阅读

使用 pytest + yaml 做接口自动化测试, 使用数据驱动的思路做,但是怎么在 yaml 文件中引用其他接口传递过来的值? 请各位高手指点

共收到 14 条回复 时间 点赞

你这种属于运行时赋值的变量,没法用 yaml 自带的变量机制实现。得用测试框架来存储,并设定一些赋值/使用变量语法给使用者在 yaml 中使用。

具体例子,建议可以看看 httprunner v1 或者 v2 版本。


yaml 里面写 ${xxxx},读完 yaml 后用 string.replace() 将 ${xxxx}替换即可

总的来说,把提取的变量,保存到一个 csv / yaml(任意形式的数据格式),运行的时候把这些变量读取出来

准备:

  1. 编写提取变量的语法,在数据驱动的时候,引用这个语法,让程序能够自动获取到该变量值,比如:$validate(变量名,哪里提取的值?)
  2. 实现获取完变量值,自动保存到数据文件
  3. 编写,使用变量的语法,如:${studentName},并且程序能够对其识别

使用:

  1. 数据驱动用例,使用该提取变量的语法(比如,后续接口需要用到 token,就可以在登录用例,提取 token,$validate('token', 'json.data.token'))
  2. 程序开始之后,自动清空,储存数据变量的文件(达到初始化作用)
  3. 程序自动识别提取变量的语法,进行提取后,自动储存(已储存:token: skj545qww1qw1sa2s)
  4. 程序在用例执行之前,自动获取该数据变量文件,读出所有的变量,并转换为可用变量(即把数据文件格式的变量,保存到对象中,这样变量就成为一个属性了,obj = { token: skj545qww1qw1sa2s } )
  5. 需要用到变量的用例,使用变量,${xx 变量名 xxx}(比如,接口用例的 header: { token: ${token} })
  6. 程序自动识别,使用变量名的用例,自动去变量中寻找对应的变量名,并替换为变量值(自动替换为:token: skj545qww1qw1sa2s)
method: get
url: http://www.baidu.com
headers:
  Content-Type: application/json
  token: $token
data:
  username: ${username}
  password: ${password}

这个是 yaml 的测试用例存储


input_data = {'token': 'hdadhh21uh1283hashdhuhh2hd', 'username': 'admin', 'password': 123456}

def operate_template(path, var):
    from string import Template
    import yaml
    file_stream = open(path, "r", encoding="utf-8")
    str_temp =Template(file_stream.read())
    new_data = str_temp.safe_substitute(var)
    data = yaml.safe_load(new_data)
    return data

result = operate_template("./temp.yaml", input_data)
print(type(result))
print(result)
pwd=result["data"]["password"]
print(type(pwd))
print(pwd)

可以使用 yaml 库读取 yaml 文件,然后通过 string 的 Template 方法替换变量
其中 input_data 可以写成全局变量,这只是个例子

Smobee 回复

看完之后似乎还是不太理解,能否举个栗子。

我现在的方法是,存在读取存在 yaml 的数据,然后我再添加需要的参数(yaml+ 自己添加的),再请求测试用例

其实使用 jinja2,都不太用写什么,代码一下就都明白了,不用太发明轮子,尤其这种模版引擎之类的

def greeting(name: str):
    return "Hello," + name;


class StructureClass(BaseModel):
    name: str = "name"
    value: str = "value"


def raw_render():
    tpl_str = """
    "Hello, {{ name.upper() }}!"
      Hello, {{ hello()}}!
      Hellom {{greet(name)}}
      Hellom {{ greet(name.upper()) }}
      Hello {{clazz.name}}
    """
    template = tpl_env.from_string(tpl_str)
    template.globals.update({
        "hello": hello_world,
        "greet": greeting
    })
    print(template.render(name="test",clazz=StructureClass()))


raw_render()

运行结果是:python 自己的函数,自己定义的函数都可以使用


"Hello, TEST!"
  Hello, hello_world!
  Hellom Hello,test
  Hellom Hello,TEST
  Hello name
zhang 回复

有个疑问,这种替换方式只适合字符串吗?比如有个字段 age=18 是整形,替换后是字符串

yaml 文件时不支持参数化的,那么需要数据参数化的话可以有这个一个思路。yaml 文件里用特定的标识表示你想参数化的数据,然后读取到 yaml 文件后,识别特定的标识,并且替换掉。

为什么执着于把中间变量存到 yaml 中。如果仅是后续函数调用,可以把变量设置成全局的,然后再后续函数中去引入即可

zhang 回复

这种方式应该不适用于 ddt 形式的数据驱动吧?ddt 读取的是 yaml 本身,那这种情况还要办法解决吗?

7楼 已删除

发现一个踩坑记录,各位可以参考下
https://blog.csdn.net/LANNY8588/article/details/123782967

tester 回复

使用 yaml 的强制转换

url: http://www.baidu.com
method: get
headers:
  Content-Type: application/json
  token: $token
data:
  username: ${username}
  password: !!str ${password}

可以看下这个在 yaml 的使用方式,可以参考这个
https://blog.csdn.net/qq_44708990/article/details/121682012

打工人 回复

适用的啊,yaml 读取出来后先处理,把处理的结果传给 ddt 就行

zhang 回复

收到,谢谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册