筛选pytest固定装置



这与以前的问题基本相同,但希望现在有更好的解决方案。

问题:给定一个参数化的fixture,如何用fixture对象的子集来参数化测试函数?

示例

import pytest
@pytest.fixture(params=range(7))
def square(request):
return request.param ** 2
def test_all_squares(square):
sqrt = square ** 0.5
assert sqrt == int(sqrt)
@pytest.fixture()
def odd_square(square):
if square % 2 == 1:
return square
pytest.skip()
def test_all_odd_squares(odd_square):
assert odd_square % 2 == 1
sqrt = odd_square ** 0.5
assert sqrt == int(sqrt)

输出

$pytest-pytests.py-v====================================================测试会话开始================================。。。收集了14个项目pytests.py::test_all_squares[0]通过[7%]pytests.py::test_all_squares[1]通过[14%]pytests.py::test_all_squares[2]通过[21%]pytests.py::test_all_squares[3]通过[28%]pytests.py::test_all_squares[4]通过[35%]pytests.py::test_all_squares[5]通过[42%]pytests.py::test_all_squares[6]通过[50%]pytests.py::test_all_odd_squares[0]跳过[57%]pytests.py::test_all_odd_squares[1]通过[64%]pytests.py::test_all_odd_squares[2]跳过[71%]pytests.py::test_all_odd_squares[3]通过[78%]pytests.py::test_all_odd_squares[4]跳过[85%]pytests.py::test_all_odd_squares[5]通过[92%]pytests.py::test_all_odd_squares[6]跳过[100%]==============================================10通过,4在0.02秒内跳过================================

尽管这很有效,但并不理想:

  • 它创建了总是被跳过的伪测试用例
  • 它需要使用过滤的fixture为参数提供不同名称(odd_square(的测试函数

我想要的是一个filter_fixture(predicate, fixture)函数,它过滤原始夹具的对象,并可以传递给pytest.mark.parametrize,类似于以下内容:

@pytest.mark.parametrize("square", filter_fixture(lambda x: x % 2 == 1, square))
def test_all_odd_squares(square):
assert square % 2 == 1
sqrt = square ** 0.5
assert sqrt == int(sqrt)

这在某种程度上可行吗?

如果您需要一定程度的逻辑来确定将哪些参数应用于每个测试,您可能需要考虑使用pytest_generate_tests挂钩。

钩子函数pytest_generate_tests是为每个收集的测试调用的。metafunc参数允许您动态地参数化每个单独的测试用例。重写您的示例以使用pytest_generate_tests可能如下所示:

def pytest_generate_tests(metafunc):
square_parameters = (x**2 for x in range(7))
if 'square' in metafunc.fixturenames:
metafunc.parametrize("square", square_parameters)
if 'odd_square' in metafunc.fixturenames:
odd_square_parameters = (x for x in square_parameters if x % 2 == 1)
metafunc.parametrize("odd_square", odd_square_parameters)
def test_all_squares(square):
sqrt = square ** 0.5
assert sqrt == int(sqrt)
def test_all_odd_squares(odd_square):
assert odd_square % 2 == 1
sqrt = odd_square ** 0.5
assert sqrt == int(sqrt)

这导致运行以下测试用例:

$ pytest -v pytests.py 
=========== test session starts ===========
…
collected 10 items
pytests.py::test_all_squares[0] PASSED                                                                                                                                                                                     [ 10%]
pytests.py::test_all_squares[1] PASSED                                                                                                                                                                                     [ 20%]
pytests.py::test_all_squares[4] PASSED                                                                                                                                                                                     [ 30%]
pytests.py::test_all_squares[9] PASSED                                                                                                                                                                                     [ 40%]
pytests.py::test_all_squares[16] PASSED                                                                                                                                                                                    [ 50%]
pytests.py::test_all_squares[25] PASSED                                                                                                                                                                                    [ 60%]
pytests.py::test_all_squares[36] PASSED                                                                                                                                                                                    [ 70%]
pytests.py::test_all_odd_squares[1] PASSED                                                                                                                                                                                 [ 80%]
pytests.py::test_all_odd_squares[9] PASSED                                                                                                                                                                                 [ 90%]
pytests.py::test_all_odd_squares[25] PASSED                                                                                                                                                                                [100%]
=========== 10 passed in 0.03s ===========

请注意,我的示例中的测试ID与您的略有不同。但是,可以使用metafunc.parametrizeìds参数提供显式测试标识符。

最新更新