【问题标题】:Pytest is skipping post yield of contextmanager when assertion fails当断言失败时,Pytest 正在跳过 contextmanager 的 post yield
【发布时间】:2018-09-12 05:23:46
【问题描述】:

我有一个自定义上下文管理器(不是固定装置)用于设置和清理测试:

@contextmanager
def db_content(*args, **kwargs):
    instance = db_insert( ... )

    yield instance

    db_delete(instance)

def test_my_test():
    with db_content( ... ) as instance:
        #  ...
        assert result

问题在于,当断言失败时,db_delete() 代码 - 即后 yield 语句,并没有被执行。

我可以看到,如果我使用固定装置,这确实有效。

@pytest.fixture
def db_instance():
    instance = db_insert( ... )

    yield instance

    db_delete(instance)

def test_my_test(db_instance):
        #  ...
        assert result

但是,固定装置非常不灵活。我想在每个测试中将不同的参数传递给我的上下文,而使用固定装置会迫使我为每种情况定义不同的固定装置。

【问题讨论】:

  • 你能展示一个实际可运行的例子吗?
  • 一个非常简单的例子:pastebin.com/aS1j7iRV
  • fixtures 可以直接(通过params arg)或间接(通过parametrize 标记)进行参数化。您在强制您编写自己的上下文管理器的固定装置上缺少什么?
  • @hoefling 事实上它们是函数的参数,这使得用各种参数制作多个夹具非常不可读

标签: python-3.x pytest yield fixtures contextmanager


【解决方案1】:

如果抛出异常,contextlib 不会执行 post-yield 语句。这是设计使然。为了让它工作,你必须写:

@contextmanager
def db_content(*args, **kwargs):
    instance = db_insert( ... )

    try:
        yield instance

    finally:
        db_delete(instance)

在我看来,这是违反直觉的,因为尝试不在于产量本身。

我采用了contextmanager 的实现,并制作了一个可以按预期工作的安全版本,但是它是一个完整的代码重复,如果有人有更好的解决方法,我很乐意看到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2011-07-15
    • 2016-07-17
    • 1970-01-01
    相关资源
    最近更新 更多