如何在多个测试函数之间共享参数化参数?

cuh*_*hor 8 pytest

我在同一个文件中有许多测试函数,它们共享一组通用的参数化参数,如下面的代码片段所示。当测试函数的数量增加 (>100) 时,为每个测试函数重复这些参数似乎效率不高,而且容易出错。pytest 中是否有任何方法可以定义一组常见的参数化参数并在所有测试中共享它?Fixture 用于注入公共数据依赖。我想知道是否有任何类似的工具可以注入通用参数

import pytest

@pytest.mark.parametrize('common_arg1', [0, 1])
@pytest.mark.parametrize('common_arg2', [2, 3])
@pytest.mark.parametrize('a', [0, 1])
def test_1(common_arg1, common_arg2, a):
    pass
    
@pytest.mark.parametrize('common_arg1', [0, 1])  # repetition
@pytest.mark.parametrize('common_arg2', [2, 3])  # repetition
@pytest.mark.parametrize('b', [0, 1])
def test_2(common_arg1, common_arg2, b):
    pass
    
...

@pytest.mark.parametrize('common_arg1', [0, 1])  # more repetition!
@pytest.mark.parametrize('common_arg2', [2, 3])  # more repetition!
@pytest.mark.parametrize('x', [0, 1])
def test_100(common_arg1, common_arg2, x):
    pass  
Run Code Online (Sandbox Code Playgroud)

Kam*_*mil 13

您可以将所有测试用例移动到一个辅助类中,并在该类的顶部放置通用装饰器。特定于某些测试(方法)的装饰器可以直接应用于它们。检查下面的示例。

import pytest


@pytest.mark.parametrize('common_arg1', [0, 1])
@pytest.mark.parametrize('common_arg2', [2, 3])
class TestParametrized:

    @pytest.mark.parametrize('a', [0, 1])
    def test_1(self, common_arg1, common_arg2, a):
        pass

    @pytest.mark.parametrize('b', [0, 1])
    def test_2(self, common_arg1, common_arg2, b):
        pass

    @pytest.mark.parametrize('x', [0, 1])
    def test_100(self, common_arg1, common_arg2, x):
        pass
Run Code Online (Sandbox Code Playgroud)


小智 8

正如 Kammil 所指出的,最好的方法是拥有一个 Test 类,作为 Kammil 方法的替代方法,是为您的测试数据添加一个类属性,通过这种方式,您可以拥有不使用 common_arg1 和 common_arg2 的测试方法你的班。但是你仍然需要标记测试,但你不需要重写所有的参数化参数,如果你改变了类属性的值,它会反映在所有测试中。

如果您要在同一类中拥有不需要 common_arg1 和 common_arg2 的测试方法,这将特别有用。

请记住,如果您装饰该类,则所有方法都必须将 common_arg1 和 common_arg2 作为参数,如果您尝试编写未在方法的 args 列表中引用它们的方法,则会出现function uses no argument 'common_arg1'错误。

所以为了避免这种情况,你可以这样做:

import pytest

class TestParametrized:

    common_args = ('common_arg1, common_arg2', [([0, 1], [2,3])])

    @pytest.mark.parametrize(*common_args)
    @pytest.mark.parametrize('a', [0, 1])
    def test_1(self, common_arg1, common_arg2, a):
        pass

    @pytest.mark.parametrize(*common_args)
    @pytest.mark.parametrize('b', [0, 1])
    def test_2(self, common_arg1, common_arg2, b):
        pass

    @pytest.mark.parametrize(*common_args)
    @pytest.mark.parametrize('x', [0, 1])
    def test_100(self, common_arg1, common_arg2, x):
        pass

    def test_1000(self):
        pass
Run Code Online (Sandbox Code Playgroud)

请注意,test_1000 会成功并且不会抱怨没有提及 common_args1 和 common_args2。您还可以通过编写两个类属性将 common_args 拆分为 2。


sma*_*rie 7

另一种方法是使用参数化pytest夹具。对于单个参数化,很容易使用 plain pytest

import pytest

@pytest.fixture(params=[0, 1])
def common_arg1(request):
    return request.param

@pytest.fixture(params=[2, 3])
def common_arg2(request):
    return request.param

@pytest.mark.parametrize('a', [0, 1])
def test_1(common_arg1, common_arg2, a):
    pass

@pytest.mark.parametrize('b', [0, 1])
def test_2(common_arg1, common_arg2, b):
    pass

@pytest.mark.parametrize('x', [0, 1])
def test_100(common_arg1, common_arg2, x):
    pass
Run Code Online (Sandbox Code Playgroud)

如果你想以更紧凑的方式编写它,你可以使用pytest_cases.param_fixture

from pytest_cases import param_fixture

common_arg1 = param_fixture('common_arg1', [0, 1])
common_arg2 = param_fixture('common_arg2', [2, 3])
Run Code Online (Sandbox Code Playgroud)

对于多个参数化,您可能希望使用以下@pytest_cases.fixture命令@pytest.mark.parametrize

import pytest
from pytest_cases import fixture

@fixture
@pytest.mark.parametrize('a', [0, 1])
@pytest.mark.parametrize('b', [2, 3])
def common_arg_multiple(a, b):
    return a * b, a - b
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅pytest-cases 文档。(我是作者;))