目录
前言:
pytest 参数化是一个非常强大的功能,可以帮助我们在测试中灵活地运行不同的测试用例。
语法
在《pytest 精通 fixture》和《pytest 内置和自定义 marker》两篇文章中,都提到了 pytest 参数化。那么本文就趁着热乎,赶紧聊一聊 pytest 的参数化是怎么玩的。
@pytest.mark.parametrize
@user1ize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
assert eval(test_input) == expected
-
可以自定义变量,test_input 对应的值是"3+5" "2+4" "6*9",expected 对应的值是 8 6 42,多个变量用 tuple,多个 tuple 用 list
-
参数化的变量是引用而非复制,意味着如果值是 list 或 dict,改变值会影响后续的 test
-
重叠产生笛卡尔积
import pytest
@user2ize("x", [0, 1])
@user3ize("y", [2, 3])
def test_foo(x, y):
pass
@pytest.fixture()
@pytest.fixture(scope="module", params=["smtp.gmail.com", "mail.python.org"])
def smtp_connection(request):
smtp_connection = smtplib.SMTP(request.param, 587, timeout=5)
-
只能使用 request.param 来引用
-
参数化生成的 test 带有 ID,可以使用
-k
来筛选执行。默认是根据函数名[参数名]
来的,可以使用 ids 来定义
// list
@pytest.fixture(params=[0, 1], ids=["spam", "ham"])
// function
@pytest.fixture(params=[0, 1], ids=idfn)
使用--collect-only
命令行参数可以看到生成的 IDs。
参数添加 marker
我们知道了参数化后会生成多个 tests,如果有些 test 需要 marker,可以用 pytest.param 来添加
marker 方式
# content of test_expectation.py
import pytest
@user7ize(
"test_input,expected",
[("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
assert eval(test_input) == expected
fixture 方式
# content of test_fixture_marks.py
import pytest
@pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)])
def data_set(request):
return request.param
def test_data(data_set):
pass
pytest_generate_tests
用来自定义参数化方案。使用到了 hook,hook 的知识我会写在《pytest hook》中,欢迎关注公众号 dongfanger 获取最新文章。
# content of conf.py
def pytest_generate_tests(metafunc):
if "test_input" in metafunc.fixturenames:
metafunc.parametrize("test_input", [0, 1])
# content of test.py
def test(test_input):
assert test_input == 0
- 定义在 conftest.py 文件中
- metafunc 有 5 个属性,fixturenames,module,config,function,cls
- metafunc.parametrize() 用来实现参数化
- 多个 metafunc.parametrize() 的参数名不能重复,否则会报错
参数化误区
在讲示例之前,先简单分享我的菜鸡行为。假设我们现在需要对 50 个接口测试,验证某一角色的用户访问这些接口会返回 403。我的做法是,把接口请求全部参数化了,test 函数里面只有断言,