过滤pytest装置 [英] Filtering pytest fixtures

查看:62
本文介绍了过滤pytest装置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is basically the same as an older question but hoping there is a better solution now.

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

The problem: Given a parametrized fixture, how can one parametrize a test function with a subset of the fixtures objects?

示例:

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
=================================================================== 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 ==============================================================

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

Although this works, it's not ideal:

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

我想要的是例如一个 filter_fixture(predicate, fixture) 函数,它过滤原始装置的对象并且可以传递给 pytest.mark.parametrize,像这样:

What I'd like instead is e.g. a filter_fixture(predicate, fixture) function that filters the original fixture's objects and can be passed to pytest.mark.parametrize, something like this:

@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钩子.

If you require a certain degree of logic to determine which parameters to apply to each test, you might want to consider using the pytest_generate_tests hook.

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

The hook function pytest_generate_tests is called for every collected test. The metafunc argument allows you to dynamically parametrize each individual test case. Rewriting your example to use pytest_generate_tests could look like this:

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)

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

This results in the following test cases being run:

$ 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 参数提供显式测试标识符.

Note that the test IDs in my example are slightly different from yours. However, you can provide explicit test identifiers using the ìds argument of metafunc.parametrize.

这篇关于过滤pytest装置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆