过滤 pytest 夹具

gsa*_*kis 5 python fixtures pytest

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

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

例子

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)

Run Code Online (Sandbox Code Playgroud)

输出

$ 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%]

=================================================== ============ 0.02 秒内10 个通过,4 个跳过 ================================ ==================================

虽然这有效,但并不理想:

  • 它创建总是被跳过的虚拟测试用例
  • odd_square它需要使用过滤后的装置的测试函数为参数提供不同的名称 ( )。

我想要的是一个filter_fixture(predicate, fixture)过滤原始灯具对象并可以传递给 的函数pytest.mark.parametrize,如下所示:

$ pytest pytests.py  -v
=================================================================== test session starts ===================================================================
...
collected 14 items                                                                                                                                        

pytests.py::test_all_squares[0] PASSED                                                                                                              [  7%]
pytests.py::test_all_squares[1] PASSED                                                                                                              [ 14%]
pytests.py::test_all_squares[2] PASSED                                                                                                              [ 21%]
pytests.py::test_all_squares[3] PASSED                                                                                                              [ 28%]
pytests.py::test_all_squares[4] PASSED                                                                                                              [ 35%]
pytests.py::test_all_squares[5] PASSED                                                                                                              [ 42%]
pytests.py::test_all_squares[6] PASSED                                                                                                              [ 50%]
pytests.py::test_all_odd_squares[0] SKIPPED                                                                                                         [ 57%]
pytests.py::test_all_odd_squares[1] PASSED                                                                                                          [ 64%]
pytests.py::test_all_odd_squares[2] SKIPPED                                                                                                         [ 71%]
pytests.py::test_all_odd_squares[3] PASSED                                                                                                          [ 78%]
pytests.py::test_all_odd_squares[4] SKIPPED                                                                                                         [ 85%]
pytests.py::test_all_odd_squares[5] PASSED                                                                                                          [ 92%]
pytests.py::test_all_odd_squares[6] SKIPPED                                                                                                         [100%]

============================================================== 10 passed, 4 skipped in 0.02s ==============================================================

这在某种程度上可行吗?

Mic*_*ert 1

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

\n

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

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

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

\n
$ pytest -v pytests.py \n=========== test session starts ===========\n\xe2\x80\xa6\ncollected 10 items\n\npytests.py::test_all_squares[0] PASSED                                                                                                                                                                                     [ 10%]\npytests.py::test_all_squares[1] PASSED                                                                                                                                                                                     [ 20%]\npytests.py::test_all_squares[4] PASSED                                                                                                                                                                                     [ 30%]\npytests.py::test_all_squares[9] PASSED                                                                                                                                                                                     [ 40%]\npytests.py::test_all_squares[16] PASSED                                                                                                                                                                                    [ 50%]\npytests.py::test_all_squares[25] PASSED                                                                                                                                                                                    [ 60%]\npytests.py::test_all_squares[36] PASSED                                                                                                                                                                                    [ 70%]\npytests.py::test_all_odd_squares[1] PASSED                                                                                                                                                                                 [ 80%]\npytests.py::test_all_odd_squares[9] PASSED                                                                                                                                                                                 [ 90%]\npytests.py::test_all_odd_squares[25] PASSED                                                                                                                                                                                [100%]\n\n=========== 10 passed in 0.03s ===========\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n