@pytest.mark.parametrize 是 pytest 提供的用于参数化的标记器,在测试函数需要不同测试数据的场景下使用。比如参数的字符类型与长度测试测试。

参数说明


@pytest.mark.parametrize 需要接收两个参数:第一个参数是字符串,里面定义参数变量;第二个参数是一个列表,列表内值是多个元组,元组的数量即是测试用例的执行次数。元组内的值需要与第一个参数字符串定义的变量对应。

比如 @pytest.mark.parametrize(“n,n1,n2”, [(1, 2, 3), (3, 4, 5), (5, 6, 7)]),被装饰得测试用例的参数需为 n,n1,n2 。

被装饰得测试用例会被执行三次。第一次执行, 1 会传给 n,2 会传给 n1,3 会传给 n3;第二次执行, 3 会传给 n,4 会传给 n1,5 会传给 n3;第三次执行, 5 会传给 n,6 会传给 n1,7 会传给 n3。

参数化基本用法


参数化单个测试用例

import pytest

@pytest.mark.parametrize("n, expected", [
    (1 + 2, 3),
    (2 + 2, 4),
    (3 * 3, 9)
])
def test_math(n, expected):
    assert n == expected

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 3 items

cases/test_a.py::test_math[3-3] PASSED                                                                                        [ 33%]
cases/test_a.py::test_math[4-4] PASSED                                                                                        [ 66%]
cases/test_a.py::test_math[9-9] PASSED                                                                                        [100%]

========================================================= 3 passed in 0.01s =========================================================

参数化测试组(组中所有的测试用例都需要被参数化)

import pytest

@pytest.mark.parametrize("n, expected", [(1, 2), (3, 4)])
class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected

    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 4 items

cases/test_a.py::TestClass::test_one[1-2] PASSED                                                                              [ 25%]
cases/test_a.py::TestClass::test_one[3-4] PASSED                                                                              [ 50%]
cases/test_a.py::TestClass::test_two[1-2] PASSED                                                                              [ 75%]
cases/test_a.py::TestClass::test_two[3-4] PASSED                                                                              [100%]

========================================================= 4 passed in 0.02s ========================================================= 

参数化模块中测试用例(模块中所有的测试用例都需要被参数化)

import pytest

pytestmark = pytest.mark.parametrize("n,expected", [(1, 2), (2, 4)])


class TestClass:
    def test_one(self, n, expected):
        assert n + n == expected

    def test_two(self, n, expected):
        assert n + n == expected

def test_three(n, expected):
    assert n+n == expected


def test_four(n, expected):
    assert n+n == expected

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 8 items

cases/test_a.py::TestClass::test_one[1-2] PASSED                                                                              [ 12%]
cases/test_a.py::TestClass::test_one[2-4] PASSED                                                                              [ 25%]
cases/test_a.py::TestClass::test_two[1-2] PASSED                                                                              [ 37%]
cases/test_a.py::TestClass::test_two[2-4] PASSED                                                                              [ 50%]
cases/test_a.py::test_three[1-2] PASSED                                                                                       [ 62%]
cases/test_a.py::test_three[2-4] PASSED                                                                                       [ 75%]
cases/test_a.py::test_four[1-2] PASSED                                                                                        [ 87%]
cases/test_a.py::test_four[2-4] PASSED                                                                                        [100%]

========================================================= 8 passed in 0.02s =========================================================

组合参数化


可以堆叠 parametrize装饰器,进行参数的组合参数化

import pytest

@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    assert y > x

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 4 items

cases/test_a.py::test_foo[2-0] PASSED                                                                                         [ 25%]
cases/test_a.py::test_foo[2-1] PASSED                                                                                         [ 50%]
cases/test_a.py::test_foo[3-0] PASSED                                                                                         [ 75%]
cases/test_a.py::test_foo[3-1] PASSED                                                                                         [100%]

========================================================= 4 passed in 0.01s ========================================================= 

会按照 x=0/y=2x=1/y=2x=0/y=3x=1/y=3的顺序组合参数化。

参数化中应用标记


可以在 parametrize 中标记单个测试实例,例如自定义的user

import pytest


@pytest.mark.parametrize(
    "n,expected",
    [("3+5", 8), ("2+4", 6), pytest.param("6*7", 42, marks=pytest.mark.user)],
)
def test_eval(n, expected):
    assert eval(n) == expected

运行 python run.py -v -m smoke,结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 3 items / 2 deselected / 1 selected

cases/test_a.py::test_eval[6*7-42] PASSED                                                                                     [100%]

================================================== 1 passed, 2 deselected in 0.01s ==================================================

参数化中使用 Fixture


@pytest.mark.parametrize 的 indirect(默认为 False ) 参数,其作用是将参数化的参数传递给同名的 fixture,由 fixture 处理后再传递给测试函数。

参数 ‘indirect = True’ 时,将参数化的参数传递给同名的 Fixture 函数

import pytest


@pytest.fixture()
def one_param_fixture(request): 
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.fixture()
def one_param_fixture2(request):
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.mark.parametrize("one_param_fixture,one_param_fixture2", [(2, 3)], indirect=True)
def test_one_param_fixture(one_param_fixture, one_param_fixture2):
    assert (one_param_fixture, one_param_fixture2) == (2, 3)

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 1 item

cases/test_a.py::test_one_param_fixture[2-3] FAILED                                                                           [100%]

============================================================= FAILURES ==============================================================
____________________________________________________ test_one_param_fixture[2-3] ____________________________________________________

...
====================================================== short test summary info ======================================================
FAILED cases/test_a.py::test_one_param_fixture[2-3] - AssertionError: assert (4, 6) == (2, 3)
========================================================= 1 failed in 0.04s =========================================================

可以看到参数化参数传递到同名的 Fixture 函数,又传递给测试函数。

参数 ‘indirect = False’(默认) 时,只将参数化的参数传递给测试函数

import pytest


@pytest.fixture()
def one_param_fixture(request): 
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.fixture()
def one_param_fixture2(request):
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.mark.parametrize("one_param_fixture,one_param_fixture2", [(2, 3)])
def test_one_param_fixture(one_param_fixture, one_param_fixture2):
    assert (one_param_fixture, one_param_fixture2) == (2, 3)

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 1 item

cases/test_a.py::test_one_param_fixture[2-3] PASSED                                                                           [100%]

========================================================= 1 passed in 0.01s =========================================================

可以看到参数化参数只传递到测试函数。

参数 indirect 为列表时,参数化参数传递给列表中的 Fixture 函数,其余只传递给测试函数

import pytest


@pytest.fixture()
def one_param_fixture(request): 
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.fixture()
def one_param_fixture2(request):
    """
    通过 request.param 获取参数值
    """
    return request.param*2

@pytest.mark.parametrize("one_param_fixture,one_param_fixture2", [(2, 3)], indirect= ["one_param_fixture2"])
def test_one_param_fixture(one_param_fixture, one_param_fixture2):
    assert (one_param_fixture, one_param_fixture2) == (2, 3)

运行结果:

======================================================== test session starts ========================================================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
configfile: pytest.toml
collected 1 item

cases/test_a.py::test_one_param_fixture[2-3] FAILED                                                                           [100%]

============================================================= FAILURES ==============================================================
____________________________________________________ test_one_param_fixture[2-3] ____________________________________________________

...
====================================================== short test summary info ======================================================
FAILED cases/test_a.py::test_one_param_fixture[2-3] - AssertionError: assert (2, 6) == (2, 3)
========================================================= 1 failed in 0.04s =========================================================

可以看到参数化参数,只传递到列表中的 Fixture 函数,其余传递给测试函数。


THEEND



© 转载需要保留原始链接,未经明确许可,禁止商业使用。CC BY-NC-ND 4.0