背景
本文总结fixture参数化
说明
pytest除了支持基本的测试用例参数化,还支持fixture参数化。当然,fixture参数化的过程与测试用例参数化有点点区别。
fixture的参数化涉及到fixture的参数params,和内置的fixture:request。
为一个参数的fixture参数化。
示例如下:为一个参数的fixture参数化。
# ./conftest.py
import pytest
data = ["https://www.baidu.com", "https://www.google.com"]
@pytest.fixture(scope='function', params = data)
def f_function(request):
print("fixture部分:{}".format(request.param))
return request.param
# ./test_case/test_func.py
import pytest
def test_add_by_func_aaa(f_function):
print("测试用例:{}".format(f_function))
# ./run_test.py
import pytest
if __name__ == '__main__':
pytest.main(['-v','-s'])
'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 items
test_case/test_func.py::test_add_by_func_aaa[https://www.baidu.com] fixture部分:https://www.baidu.com
测试用例:https://www.baidu.com
PASSED
test_case/test_func.py::test_add_by_func_aaa[https://www.google.com] fixture部分:https://www.google.com
测试用例:https://www.google.com
PASSED
============================== 2 passed in 0.03s ==============================
[Finished in 1.4s]
'''
其中,
@pytest.fixture()中的params接收一个参数序列(列表或元组都可)。而requset是内置fixture之一,它的一个属性param每次被传入params序列中的一个元素。
从以上示例看出,fixture有一个参数,参数化时,我们为其提供了两个参数。如果这是在测试用例中,意味着这个fixture会根据两个参数执行两次。
但是fixture对象是供测试用例请求用的,所以不能只考虑fixture,需要结合请求该fixture的测试用例考虑
本示例中,test_add_by_func_aaa请求了该fixture,由于fixture的参数有2组数据,所以该用例也执行了2次。
为多个参数的fixture参数化。
如果是多个参数的fixture该怎样参数化呢,fixture的参数params接收的是一个参数序列,那么字典列表、字典元组这些都是序列,所以,我们可以借助字典来对多个参数进行参数化。
示例:
# ./conftest.py
import pytest
data = [
{"url":"https://www.baidu.com","http":"get"},
{"url":"https://www.google.com", "http":"post"}
]
@pytest.fixture(scope='function', params = data)
def f_function(request):
print("fixture部分-url:{}".format(request.param['url']))
print("fixture部分-http:{}".format(request.param['http']))
return request.param
# ./test_case/test_func.py
import pytest
def test_add_by_func_aaa(f_function):
print("测试用例-url:{}".format(f_function['url']))
print("测试用例-http:{}".format(f_function['http']))
# ./run_test.py
import pytest
if __name__ == '__main__':
pytest.main(['-v','-s'])
'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 items
test_case/test_func.py::test_add_by_func_aaa[f_function0] fixture部分-url:https://www.baidu.com
fixture部分-http:get
测试用例-url:https://www.baidu.com
测试用例-http:get
PASSED
test_case/test_func.py::test_add_by_func_aaa[f_function1] fixture部分-url:https://www.google.com
fixture部分-http:post
测试用例-url:https://www.google.com
测试用例-http:post
PASSED
============================== 2 passed in 0.05s ==============================
[Finished in 1.5s]
'''
如果你仔细的话,会发现这一点:
test_case/test_func.py::test_add_by_func_aaa[f_function0]
test_case/test_func.py::test_add_by_func_aaa[f_function1]
由于有两组参数,test_add_by_func_aaa测试用例会执行两遍,标识测试用例的标志编程了fixture名字加一个数字,不能很直观的反应这两个用例有啥区别。
所以,我们需要了解fixture的另一个参数:ids
fixture的参数:ids。为每一组参数打上标识。
该参数的作用,就是为了解决当多个参数的多组数据时,测试用例的标识问题的。
ids,顾名思义,就是为每一组测试参数指定一个独特的id,所以ids也是一个id列表,其长度和params的长度应该是一致的。
见示例:
# ./conftest.py
import pytest
data = [
{"url":"https://www.baidu.com","http":"get"},
{"url":"https://www.google.com", "http":"post"}
]
ids = ['get_baidu', 'post_google']
@pytest.fixture(scope='function', params = data, ids = ids)
def f_function(request):
print("fixture部分-url:{}".format(request.param['url']))
print("fixture部分-http:{}".format(request.param['http']))
return request.param
# ./test_case/test_func.py
import pytest
def test_add_by_func_aaa(f_function):
print("测试用例-url:{}".format(f_function['url']))
print("测试用例-http:{}".format(f_function['http']))
# ./run_test.py
import pytest
if __name__ == '__main__':
pytest.main(['-v','-s'])
'''
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.4, py-1.8.1, pluggy-0.13.1 -- D:\Python3.7\python.exe
cachedir: .pytest_cache
rootdir: D:\Python3.7\project\pytest, inifile: pytest.ini
plugins: allure-pytest-2.8.9, rerunfailures-8.0
collecting ... collected 2 items
test_case/test_func.py::test_add_by_func_aaa[get_baidu] fixture部分-url:https://www.baidu.com
fixture部分-http:get
测试用例-url:https://www.baidu.com
测试用例-http:get
PASSED
test_case/test_func.py::test_add_by_func_aaa[post_google] fixture部分-url:https://www.google.com
fixture部分-http:post
测试用例-url:https://www.google.com
测试用例-http:post
PASSED
============================== 2 passed in 0.04s ==============================
[Finished in 1.5s]
'''
最后
想象这样一个场景,fixture的名字和测试用例的参数名字是一样的,那么测试用例执行时是把它当作fixture呢,还是参数呢。
对于该场景,pytest也有相应的处理。
但是这里不作这方面的总结,因为,我认为我自己反正是干不出把fixture和参数取同一个名字这种事情的。