这3种pytest固定装置在功能上有什么区别?

时间:2019-01-18 16:00:08

标签: python unit-testing pytest

我对pytest风格的单元测试还比较陌生,并且我想了解有关pytest固定装置的更多信息。我没有将范围参数传递给灯具,因此我知道范围是“函数”。这三种简单灯具的功能是否有所不同?为什么会偏爱一种方法?

@pytest.fixture()
@patch('a.b.c.structlog.get_logger')
def fixture_classQ(mock_log):
    handler = MagicMock(spec=WidgetHandler)
    return ClassQ(handler)
@pytest.fixture()
def fixture_classQ():
    with patch('a.b.c.structlog.get_logger'):
        handler = MagicMock(spec=WidgetHandler)
        return ClassQ(handler)
@pytest.yield_fixture()
def fixture_classQ():
    with patch('a.b.c.structlog.get_logger'):
        handler = MagicMock(spec=WidgetHandler)
        yield ClassQ(handler)

灯具的简单使用示例:

def test_classQ_str(fixture_classQ):
    assert str(fixture_classQ) == "This is ClassQ"

谢谢。

1 个答案:

答案 0 :(得分:0)

装置1

从第一个开始,这将创建一个纯数据夹具。该模拟(误导性的imo)仅在fixture函数期间有效,因为它使用return

为了大致了解发生了什么:

  • pytest注意到您的灯具已用于测试功能
  • 它调用夹具功能
    • 模拟装饰器启动补丁
    • 模拟装饰器调用您的实际函数(返回一个值)
    • 模拟装饰器撤消补丁
  • pytest注意到它不是生成器,所以这就是灯具的价值

装置2

第二个在行为上与第一个相同,除了它使用mock的上下文管理器形式而不是装饰器。我个人不喜欢装饰器形式,但是那只是我:D

装置3

(首先,我继续使用pytest.yield_fixturepytest.fixture的不推荐使用的别名-您可以只使用@pytest.fixture

第三个功能有所不同!补丁在测试过程中是有效的,因为它在固定期间已“屈服”。这是一种整体创建安装和拆卸夹具的方法。这大概是这里的执行情况

  • pytest注意到您的灯具已用于测试功能
  • pytest调用fixture函数
    • 因为它是生成器,所以它立即返回而无需执行代码
  • pytest注意到它是一个生成器,在其上调用next(...)
    • 这将导致代码执行到yield,然后“暂停”。您可以将其视为一种例行程序
    • __enter__中的mock被称为激活补丁
    • yield的值用作灯具的值
  • pytest然后执行您的测试功能
  • pytest然后再次在生成器上调用next(...)以耗尽固定装置
    • __exit__的with语句,撤消补丁程序

要选择哪个?

最好的答案是这取决于。由于1和2在功能上等效,因此取决于个人喜好。如果需要在整个测试过程中激活补丁,请选择3.。而且不要使用pytest.yield_fixture,只需使用pytest.fixture