如何对单个测试中使用的多个夹具应用间接参数化?

2024-06-26 11:04:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我想为单个测试间接地参数化多个装置,这与“对特定参数应用间接”下的pytest documentation中描述的非常相似

测试代码大致如下所示:

import pytest

@pytest.fixture
def getDataA(request):
    """Expensive method to call data A (utilizing request.param)"""
    if (request.param = "DetailedDataElementinA"):
        return True

@pytest.fixture
def getDataB(request):
    """Expensive method to call data B (utilizing request.param)"""
    if (request.param = "DetailedDataElementinB"):
        return True


@pytest.mark.parametrize("getDataA, getDataB ", ["DetailedDataElementinA", " DetailedDataElementinB"], indirect=["getDataA ", "getDataB"])
def test_comparedata(getDataA, getDataB):
    """Test that compares specific elements (detailed in request param) of two data sets"""
    assert(getDataA == getDataB)

我的问题是@pytest.mark.parametrize。pytest文档中的示例仅使用一个间接参数化,而我使用两个间接参数化。我尝试了几种不同的语法结构,但迄今为止我没有成功,我收到了如下错误消息:

  • “E TypeError:Parameterize()为参数获取了多个值 “间接的”
  • 在“参数化”中,名称的数量必须相等 “值的数量”

有人知道哪种语法可能有效吗


Tags: todata参数ifparampytestrequestdef
2条回答

使用indirect=['getDataA', 'getDataB']应该是可行的,因为它应该是pass a list or tuple of arguments’ names to ^{} for fixtures to indirectly parametrize。但是,根据您当前的代码:

@pytest.mark.parametrize("getDataA, getDataB ", ["DetailedDataElementinA", " DetailedDataElementinB"], indirect=["getDataA ", "getDataB"])
def test_comparedata(getDataA, getDataB):
    assert(getDataA == getDataB)

您有2个间接参数化装置,但在每次测试运行时,您只有1个参数值传递给它。^{}的第二个参数应该是要传递给每个测试运行上的每个夹具的参数值:

If N argnames were specified, argvalues must be a list of N-tuples, where each tuple-element specifies a value for its respective argname.

第一次运行将尝试将"DetailedDataElementinA"传递到2个装置中,并将失败:

test.py::test_comparedata: in "parametrize" the number of names (2):
  ['getDataA', 'getDataB']
must be equal to the number of values (22):
  DetailedDataElementinA

因为它期望每个装置有2个值,1

按照方法的描述,由于存在2个装置,因此每个装置需要2个-元组值,1个

这里我简化了示例fixture,使fixture只返回param值,然后让断言无法看到getDataAgetDataB的实际返回值)

@pytest.fixture
def getDataA(request):
    return request.param.replace('ThisWillBePassedTo', 'FixtureReceived')

@pytest.fixture
def getDataB(request):
    return request.param.replace('ThisWillBePassedTo', 'FixtureReceived')

@pytest.mark.parametrize(
    'getDataA, getDataB',
    [
        ('ThisWillBePassedToA-1', 'ThisWillBePassedToB-1'),
        ('ThisWillBePassedToA-2', 'ThisWillBePassedToB-2'),
        ('ThisWillBePassedToA-3', 'ThisWillBePassedToB-3'),
    ],
    indirect=['getDataA', 'getDataB'],
)
def test_comparedata(getDataA, getDataB):
    assert (getDataA == getDataB)

应该有3个测试(3个元组),每次运行时,索引[0]处的元组元素将传递给getDataA,索引[1]处的元组元素将传递给getDataB,顺序与定义夹具的顺序相同:

test.py::test_comparedata[ThisWillBePassedToA-1-ThisWillBePassedToB-1] FAILED [ 33%]
test.py::test_comparedata[ThisWillBePassedToA-2-ThisWillBePassedToB-2] FAILED [ 66%]
test.py::test_comparedata[ThisWillBePassedToA-3-ThisWillBePassedToB-3] FAILED [100%]

getDataA = 'FixtureReceivedA-1', getDataB = 'FixtureReceivedB-1'
>       assert (getDataA == getDataB)
E       AssertionError: assert 'FixtureReceivedA-1' == 'FixtureReceivedB-1'
E         - FixtureReceivedB-1
E         ?                ^
E         + FixtureReceivedA-1
E         ?     

getDataA = 'FixtureReceivedA-2', getDataB = 'FixtureReceivedB-2'
>       assert (getDataA == getDataB)
E       AssertionError: assert 'FixtureReceivedA-2' == 'FixtureReceivedB-2'
E         - FixtureReceivedB-2
E         ?                ^
E         + FixtureReceivedA-2
E         ? 

虽然这样做有效,但当你有很多固定装置时可能会出现问题,因为你必须自己列出所有不同的组合,而且依赖顺序也会让人困惑

您可以改为使用stack the parametrized tests,它将获得所有参数组合:

@pytest.fixture
def getDataA(request):
    return request.param.replace('ThisWillBePassedTo', 'FixtureReceived')

@pytest.fixture
def getDataB(request):
    return request.param.replace('ThisWillBePassedTo', 'FixtureReceived')

@pytest.mark.parametrize(
    'getDataB',
    [
        'ThisWillBePassedToB-1',
        'ThisWillBePassedToB-2',
        'ThisWillBePassedToB-3',
    ],
    indirect=True,
)
@pytest.mark.parametrize(
    'getDataA',
    [
        'ThisWillBePassedToA-1',
        'ThisWillBePassedToA-2',
        'ThisWillBePassedToA-3',
    ],
    indirect=True,
)
def test_comparedata(getDataA, getDataB):
    assert (getDataA == getDataB)

在这里,您可以简单地使用普通的indirect=True,参数值更清晰,仅用于getDataA或仅用于getDataB。参数化仍然遵循一个顺序:最里面的parametrized fixture也应该是传递给函数的最里面/第一个fixture。然后它会向外扩散

运行该命令将导致:

test.py::test_comparedata[ThisWillBePassedToA-1-ThisWillBePassedToB-1] ...
test.py::test_comparedata[ThisWillBePassedToA-1-ThisWillBePassedToB-2] ...
test.py::test_comparedata[ThisWillBePassedToA-1-ThisWillBePassedToB-3] ...
test.py::test_comparedata[ThisWillBePassedToA-2-ThisWillBePassedToB-1] ...
test.py::test_comparedata[ThisWillBePassedToA-2-ThisWillBePassedToB-2] ...
test.py::test_comparedata[ThisWillBePassedToA-2-ThisWillBePassedToB-3] ...
test.py::test_comparedata[ThisWillBePassedToA-3-ThisWillBePassedToB-1] ...
test.py::test_comparedata[ThisWillBePassedToA-3-ThisWillBePassedToB-2] ...
test.py::test_comparedata[ThisWillBePassedToA-3-ThisWillBePassedToB-3] ...

getDataA = 'FixtureReceivedA-1', getDataB = 'FixtureReceivedB-3'
>       assert (getDataA == getDataB)
E       AssertionError: assert 'FixtureReceivedA-1' == 'FixtureReceivedB-3'
E         - FixtureReceivedB-3
E         ?                ^ ^
E         + FixtureReceivedA-1
E         ?      

您不是在特定参数上使用间接变量,而是在所有参数上使用间接变量,因此最简单的方法是使用indirect=True。除此之外,您的版本也应该工作,您的代码中只有几个错误

主要问题是您提供了两个单独的值,它们被解释为用于参数化的两个不同的值。您必须提供值的元组,因为您有两个参数。在您的示例中,只有一个元组:

@pytest.mark.parametrize("getDataA, getDataB",
                         [("DetailedDataElementinA", "DetailedDataElementinB")],
                         indirect=True)
def test_comparedata(getDataA, getDataB):
    assert getDataA == getDataB

第二个问题是在字符串中放入一些随机空间。空格是字符串的一部分,但这也可能是您在复制代码时出错的原因(例如,您在fixture中使用的赋值而不是比较)

(这有助于将工作代码粘贴到问题中,否则很难理解什么是真正的错误,什么只是打字错误)

相关问题 更多 >