在pytest yield fixture

时间:2016-07-20 18:50:22

标签: python pytest fixtures

我有几个pytest测试用例需要几乎相同的设置,所以我想让他们重用一个fixture来保持DRY。设置涉及在外部故障单跟踪系统中创建新故障单,然后测试用例根据数据与故障单进行交互,最后通过关闭故障单来清除设备。这里的挑战是每个测试用例需要稍微不同的数据才能在故障单中准备好。

每个测试用例都有不同的调用和不同的断言,因此我无法将它们全部组合到一个带有单个测试夹具的参数化测试用例中。参数化夹具本身将导致每个测试用例运行夹具数据的每个排列,最终导致许多无关的测试失败。

我想要做的是在测试用例中设置一个变量,然后让夹具在创建故障单时使用该变量来设置测试数据。我尝试使用pytest fixture docs中指定的request.function,但我一直在:

=================================== ERRORS ===================================
    ____________________ ERROR at setup of TestMCVE.test_stuff ___________________

request = <SubRequest 'ticket' for <Function 'test_stuff'>>

    @pytest.yield_fixture
    def ticket(request):
>       ticket_summary = getattr(request.function, "summary")
E       AttributeError: 'function' object has no attribute 'summary'

tests\test_mcve.py:11: AttributeError

我的代码是:

import pytest


def ticket_system_api(summary):
    # stub for MCVE purposes
    return summary


@pytest.yield_fixture
def ticket(request):
    ticket_summary = getattr(request.function, "summary")
    new_ticket = ticket_system_api(summary=ticket_summary)
    yield new_ticket


class TestMCVE:
    def test_stuff(self, ticket):
        summary = 'xyz'
        # do real things here, except MCVE
        assert 'xyz' == ticket

我尝试使用request.node代替request.function以及binding the summary variable per this answer,将summary = 'xyz'更改为test_stuff.summary = 'xyz',但这些仍然会因同一个AttributeError而失败。

如何将功能级别数据传递给灯具?

1 个答案:

答案 0 :(得分:1)

您可以使用indirect parametrization完成此操作。 API(和文档)可能更友好,但您需要的功能就在那里。

你的例子非常接近,需要进行微调。看看:

import pytest


def ticket_system_api(summary):
    # stub for MCVE purposes
    return summary


@pytest.fixture
def ticket(request):
    # NOTE: This will raise `AttributeError` if the fixture
    # doesn't receive a parameter.
    ticket_summary = request.param
    new_ticket = ticket_system_api(summary=ticket_summary)
    return new_ticket


class TestMCVE:
    @pytest.mark.parametrize('ticket', ('abc',), indirect=True)
    def test_abc(self, ticket):
        # do real things here, except MCVE
        assert ticket == 'abc'

    @pytest.mark.parametrize('ticket', ('xyz',), indirect=True)
    def test_xyz(self, ticket):
        # do real things here, except MCVE
        assert ticket == 'xyz'