【问题标题】:AttributeError when using request.function in pytest yield fixture在 pytest yield 夹具中使用 request.function 时出现 AttributeError
【发布时间】:2016-07-20 18:50:21
【问题描述】:

我有几个 pytest 测试用例需要几乎相同的设置,所以我想让它们重用一个夹具来保持干燥。设置包括在外部工单跟踪系统中创建新工单,然后测试用例根据数据与工单交互,最后通过关闭工单来清理夹具。这里的挑战是每个测试用例需要在票证中准备稍微不同的数据。

每个测试用例都有不同的调用和不同的断言,所以我不能将它们全部组合成一个带有单个测试夹具的参数化测试用例。对夹具本身进行参数化会导致每个测试用例运行夹具数据的每个排列,最终导致很多不相关的测试失败。

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

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

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

【问题讨论】:

  • 在 "ticket" 夹具中 yield 之前的语句将在创建 "summary" 对象之前执行
  • 这里,ticket 将比测试函数先执行。夹具执行完成后,summary 将被初始化。你不能用ticket作为一个普通函数来代替fixture吗?

标签: python pytest fixtures


【解决方案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'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 2017-11-23
    • 2016-07-27
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多