如何在pytest中使用参数化的依赖夹具两次?

时间:2019-01-04 18:53:56

标签: python pytest fixtures

我试图在一次测试中多次使用参数化的夹具,目的是获得所有值的笛卡尔积。

https://stackoverflow.com/a/39444098/102441展示了如何通过简单的夹具实现此目的:

import pytest

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

second = first

# runs 3x3 = 9 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

但是,如果参数化来自于依赖的夹具,则这种方法会分崩离析:

import pytest

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

@pytest.fixture
def squared_integer(integer):
    return integer * integer

@pytest.fixture
def first(squared_integer):
    return squared_integer

second = first

# runs only 3 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

如何像简单的示例一样进行3x3运行测试?

2 个答案:

答案 0 :(得分:1)

这是pytest的正确行为。因为您在其他灯具的内部使用了integer。要了解会发生什么,请使用--setup-show标志检查pytest。您会看到类似:

        SETUP    F integer[0]
        SETUP    F squared_integer (fixtures used: integer)
        SETUP    F first (fixtures used: squared_integer)
        SETUP    F second (fixtures used: squared_integer)
        Test/test_54044536_3.py::test_double_fixture[0] (fixtures used: first, integer, second, squared_integer)F
        TEARDOWN F second
        TEARDOWN F first
        TEARDOWN F squared_integer
        TEARDOWN F integer[0]

因此,整数值仅适用于squared_integer函数。

为回答您的问题,我们可以将您的代码重构为fixture和一个函数。看起来像:

import pytest

def squared_integer(integer):
    return integer * integer


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

second = first

# runs only 3 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

您将按照以下顺序进行9个测试:

        SETUP    F first[0]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[0-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[0]
        SETUP    F first[0]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[0-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[0]
        SETUP    F first[0]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[0-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[0]
        SETUP    F first[1]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[1-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[1]
        SETUP    F first[1]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[1-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[1]
        SETUP    F first[1]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[1-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[1]
        SETUP    F first[2]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[2-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[2]
        SETUP    F first[2]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[2-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[2]
        SETUP    F first[2]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[2-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[2]

答案 1 :(得分:0)

如果您对顶级灯具的副本没有问题(在本例中,squared_integer的化身为第一和第二),您也可以复制低级灯具并将其用作灯具的另一个输入顶层一:

import pytest

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

@pytest.fixture
def squared_integer(integer, integer2):
    return integer * integer2
second = first = squared_integer

# runs 9 times
def test_double_fixture_lowlevel(integer, integer2):
    assert False, '{} {}'.format(integer, integer2)

# also runs 9 times
def test_double_fixture_toplevel(first, second):
    assert False, '{} {}'.format(first, second)