pytest:用例之间共享参数

一般情况下自动化用例只需要登录一次就行了,每个接口请求时使用同一个token即可。

实现有3种方法:

方法1:使用系统变量

属于python内置方法,简单,但是用例之间会有很多参数需要传递,不能区分是哪个用例的变量

conftest.py文件中定义登录请求,作用域设置为全局scope="session",执行时只需登录一次,获取到cookie后将其存入到系统变量,后续可进行全局使用
使用os.environ将字符串存入系统变量(注意此处只能接受str,不能接受字典)

@pytest.fixture(scope="session", autouse=True)
def get_token():
    """
    :return: 返回接口所需token
    """
    payload = {"name":hello,"pwd":123456}
    headers = settings.HEADERS
    response = requests.post(settings.host + settings.get_token_uri, data=payload, headers=headers)
    log.logger.info(f"登录接口返回:{response.text}")
    os.environ["token"] = json.loads(response.text)["data"]["accessToken"]

 读取系统变量:

headers['Authorization'] = "Bearer " + os.getenv("token")

方法2:自定义方法

可以支持每个用例对应参数,避免参数名重复

编写模块:dependency_variable.py

import json
from simple_settings import settings


def set_dependency_variable(case_name, dependency_data):
    """
    写入依赖数据
    :param case_name: 用例名
    :param dependency_data: 其他用例需要依赖的数据
    :return:
    """
    with open(settings.BASE_PATH + "/" + "common/dependency_data.json", "r") as f:
        dependency_data_dict = json.load(f)
        dependency_data_dict[case_name] = dependency_data
        f.close()
    with open(settings.BASE_PATH + "/" + "common/dependency_data.json", "w") as r:
        json.dump(dependency_data_dict, r)
        r.close()


def get_dependency_variable(depends_case, dynamic_variable):
    """
    取依赖用例的参数
    :param depends_case: 依赖的用例方法名
    :param dynamic_variable: 需要动态替换的参数
    :return: dynamic_variable:返回动态参数值
    """
    with open(settings.BASE_PATH + "/" + "common/dependency_data.json", "r") as f:
        dependency_data_dict = json.load(f)
        dynamic_variable = dependency_data_dict[depends_case][dynamic_variable]
        f.close()
        return dynamic_variable

使用时,按照python正常的调用方法即可

# 写入后续会用到的被依赖参数,第二个参数可以是字典,其中可存储多个参数供后续用例使用
set_dependency_variable(case_name, {"userID": json.loads(res.text)["data"]["userID"]})

# 读取依赖参数,第一个参数为用例名
userID= get_dependency_variable("test_edec_search", "userID")

 

方法3:使用tmpdir_factory方法

使用pytest的tmpdir和tmpdir_factory两个夹具函数,同样是通过conftest文件来实现。仍然是先来看下官方文档针对这两个方法的说明:

 

 

 简单来说,这两个方法的作用就是为每个测试方法创建一个临时目录用于存储自定义的文件,这个临时目录会默认保存3个sessions,之后就会按照创建的顺序删除旧的目录。看下官方的例子:

# content of test_tmpdir.py
def test_create_file(tmpdir):
    p = tmpdir.mkdir("sub").join("hello.txt")
    p.write("content")
    assert p.read() == "content"
    assert len(tmpdir.listdir()) == 1
    assert 0
# contents of conftest.py
import pytest
 
 
@pytest.fixture(scope="session")
def image_file(tmpdir_factory):
    img = compute_expensive_image()
    fn = tmpdir_factory.mktemp("data").join("img.png")
    img.save(str(fn))
    return fn
 
 
# contents of test_image.py
def test_histogram(image_file):
    img = load_image(image_file)
    # compute and test histogram

在实际项目中的使用:

仍是在conftest.py文件中自定义一个夹具函数,返回结果是一个元组,p是tmpdir_factory方法返回的对象,转为字符串之后就是文件存储的路径。

自定义一个名为“apitest-tmp-dir”的文件夹用于存储文件

# conftest.py
 
@pytest.fixture
def tmp_factory(tmpdir_factory):
    """
    生成临时目录
    """
    p = tmpdir_factory.mktemp('apitest-tmp-dir')
    logger.info("当前临时文件的目录为:" + str(p))
    return p, str(p)

在测试方法中的使用

 
# test_get_set.py
 
import requests
import pytest
import json
 
 
def test_set(tmp_factory):
    res = requests.get("http://www.baidu.com")
    status_code = res.status_code
    logger.info(f"返回状态码:{status_code}")
 
    logger.debug(tmp_factory)
    # 创建test_set.txt文件
    a = tmp_factory[0].join("test_set.txt")
    # 将需要的内容写入到文件中
    a.write({"status_code": status_code})
    
    # 使用read()方法获取文件中的内容
    logger.debug(a.read())
 
 
 
if __name__ == '__main__':
    pytest.main(['-sv', 'test_get_set.py'])

返回结果: 

test_get_set.py::test_set 2021-12-24 18:24:39.292 | INFO     | cases.conftest:tmp_factory:150 - 当前临时文件的目录为:/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0

2021-12-24 18:24:39.347 | INFO     | cases.test_get_set:test_set:32 - 返回状态码:200

2021-12-24 18:24:39.347 | DEBUG    | cases.test_get_set:test_set:34 - (local('/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0'), '/private/var/folders/_f/1d0lt83x1599bf6mcfppbwp40000gn/T/pytest-of-j/pytest-19/apitest-tmp-dir0')

2021-12-24 18:24:39.348 | DEBUG    | cases.test_get_set:test_set:38 - {'status_code': 200}

PASSED



============================== 1 passed in 0.07s ==============================

创建的文件:

pytest用例间参数传递的两种实现方式是怎样的

可以看到,tmpdir_factory会自动为我们创建一个目录,名字是`tmp_factory`方法中自定义的名称后面加0,同时它的上级目录会自动从pytest-0递增

说下这个办法的优缺点:

  • 先说优点,这种数据存储是直接写入到文件,因此即使运行结束后也可以访问,而不像第一种方法存储的内容会随着用例运行的结束而消失

  • 再说缺点,因为这个临时目录最多只能保存3个,因此如果用例很多时,那么就可能存在文件被自动删除的风险。不过这个貌似可以通过修改默认配置来解决,可以继续研究下。

  • 缺点二,上面的例子中,直接通过a.read()就访问到了文件中的内容,这是因为内容的存储与读取全是在一个方法内,因此可以直接调用。如果是A方法存结果,在B中需要读取,那么便不能直接使用read()方法了(因为每个方法都会创建一个目录,并且默认的读取地址都是这个方法自己创建的目录)。就需要我们自己去单独封装一个读取文件的方法了,实现起来也不难而且tmpdir本身的这些方法也是对os.path一些方法的二次封装。

话说回来,都需要我自己去封装一个读取文件的方法了,为啥不干脆把读、写都自己来做呢?这样是否删除文件、删除几个、什么时候删除就完全由自己定义了啊,貌似会更方便。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章