如何在py.test中将几个参数化夹具连接成一个新的夹具?

时间:2014-06-21 10:26:04

标签: python fixtures pytest

如果我有两个参数化灯具,我怎样才能创建一个单独的测试函数,该函数首先使用一个灯具的实例调用,然后使用另一个灯具的实例调用?

我想创建一个以某种方式连接两个现有灯具的新灯具是有意义的。这适用于“普通”灯具,但我似乎无法使用参数化灯具。

以下是我尝试过的简化示例:

import pytest

@pytest.fixture(params=[1, 2, 3])
def lower(request):
    return "i" * request.param

@pytest.fixture(params=[1, 2])
def upper(request):
    return "I" * request.param

@pytest.fixture(params=['lower', 'upper'])
def all(request):
    return request.getfuncargvalue(request.param)

def test_all(all):
    assert 0, all

当我运行时,我收到此错误:

request = <SubRequest 'lower' for <Function 'test_all[lower]'>>

    @pytest.fixture(params=[1, 2, 3])
    def lower(request):
>       return "i" * request.param
E       AttributeError: 'SubRequest' object has no attribute 'param'

...和upper()的错误相同。

我做错了什么?

我该如何解决这个问题?


更新

有一个PyTest插件可用于解决此问题:https://github.com/TvoroG/pytest-lazy-fixture

pip - 安装此插件后,对上述代码的唯一必要更改如下:

@pytest.fixture(params=[pytest.lazy_fixture('lower'),
                        pytest.lazy_fixture('upper')])
def all(request):
    return request.param

但请注意,与当前的PyTest版本3.6.3不兼容,请参阅https://github.com/TvoroG/pytest-lazy-fixture/pull/27

相关的PyTest问题:

2 个答案:

答案 0 :(得分:2)

它并不美丽,但今天你可能知道更好的方式。

请求对象内部&#39;所有&#39;夹具只知道自己的params:&#39; lower&#39;,&#39; upper&#39;。一种方式using fixtures from a fixture function

import pytest

@pytest.fixture(params=[1, 2, 3])
def lower(request):
    return "i" * request.param

@pytest.fixture(params=[1, 2])
def upper(request):
    return "I" * request.param

@pytest.fixture(params=['lower', 'upper'])
def all(request, lower, upper):
    if request.param == 'lower':
        return lower
    else:
        return upper

def test_all(all):
    assert 0, all

答案 1 :(得分:0)

pytest-cases中现在有一个名为fixture_union的解决方案。这是创建示例中要求的夹具联合的方法:

from pytest_cases import fixture_union, pytest_fixture_plus

@pytest_fixture_plus(params=[1, 2, 3])
def lower(request):
    return "i" * request.param

@pytest_fixture_plus(params=[1, 2])
def upper(request):
    return "I" * request.param

fixture_union('all', ['lower', 'upper'])

def test_all(all):
    print(all)

它按预期工作:

<...>::test_all[lower-1] 
<...>::test_all[lower-2] 
<...>::test_all[lower-3] 
<...>::test_all[upper-1] 
<...>::test_all[upper-2] 

请注意,在上例中,我使用了pytest_fixture_plus,因为如果您使用pytest.fixture,您将不得不自己处理未实际使用灯具的情况。例如,对于upper固定装置,执行以下操作:

import pytest
from pytest_cases import NOT_USED

@pytest.fixture(params=[1, 2])
def upper(request):
    # this fixture does not use pytest_fixture_plus 
    # so we have to explicitly discard the 'NOT_USED' cases
    if request.param is not NOT_USED:
        return "I" * request.param

有关详细信息,请参见documentation。 (顺便说一下,我是作者;))