Unit testing 导致pytest自动使用夹具测试失败

Unit testing 导致pytest自动使用夹具测试失败,unit-testing,pytest,fixtures,Unit Testing,Pytest,Fixtures,pytest允许创建自动应用于测试套件中每个测试的装置(通过autouse关键字参数)。这对于实现影响每个测试用例的设置和拆卸操作非常有用。有关更多详细信息,请参阅 理论上,相同的基础设施对于验证每次测试运行后预期存在的post条件也非常有用。例如,可能每次测试运行时都会创建一个日志文件,我希望在测试结束时确保它存在 不要挂断细节,但我希望你能了解基本的想法。关键是,将此代码添加到每个测试功能中会非常繁琐和重复,特别是当autouse夹具已经提供了将此操作应用于每个测试的基础结构时。此外,fix

pytest
允许创建自动应用于测试套件中每个测试的装置(通过
autouse
关键字参数)。这对于实现影响每个测试用例的设置和拆卸操作非常有用。有关更多详细信息,请参阅

理论上,相同的基础设施对于验证每次测试运行后预期存在的post条件也非常有用。例如,可能每次测试运行时都会创建一个日志文件,我希望在测试结束时确保它存在

不要挂断细节,但我希望你能了解基本的想法。关键是,将此代码添加到每个测试功能中会非常繁琐和重复,特别是当
autouse
夹具已经提供了将此操作应用于每个测试的基础结构时。此外,fixture可以打包成插件,所以我的支票可以被其他包使用

问题在于,夹具似乎不可能导致测试失败。考虑下面的例子:

@pytest.fixture(autouse=True)
def check_log_file():
    # Yielding here runs the test itself
    yield

    # Now check whether the log file exists (as expected)
    if not log_file_exists():
        pytest.fail("Log file could not be found")
在日志文件不存在的情况下,我不会得到测试失败。相反,我得到了一个pytest错误。如果在我的测试套件中有10个测试,并且所有测试都通过了,但是其中5个缺少一个日志文件,那么我将获得10个通过和5个错误。我的目标是5次通过,5次失败


所以第一个问题是:这可能吗?我是不是错过了什么?我觉得这可能是不可能的。如果是这样的话,第二个问题是:还有别的办法吗?如果这个问题的答案也是“不”:为什么不呢?这是
pytest
基础架构的基本限制吗?如果没有,那么是否有支持此类功能的计划?

在pytest中,一个
屈服
-ing夹具在设置期间执行其定义的前一半,在拆卸期间执行后一半。此外,设置和拆卸不被视为任何单独测试的一部分,因此不会导致其失败。这就是为什么您会将异常报告为附加错误,而不是测试失败


从哲学的角度讲,尽管您尝试的方法可能(聪明地)很方便,但我认为它违反了测试设置和拆卸的精神,因此即使您可以这样做,您也不应该这样做。设置和拆卸阶段的存在是为了支持测试的执行,而不是补充其对系统行为的断言。如果行为足够重要,可以断言,那么断言就足够重要,可以驻留在一个或多个专用测试的主体中


如果您只是想尽量减少代码的重复,我建议将断言封装在助手方法中,例如,
assert\u log\u file\u cleaned\u up()
,可以从适当的测试主体中调用该方法。这将允许测试机构保留其作为系统行为规范的描述能力。

AFAIK不可能告诉
pytest
将特定夹具中的错误视为测试失败

我也有一个例子,我想使用fixture来最小化测试代码的重复,但在您的例子中,这可能是一种方法


此外,测试依赖关系对于非单元测试来说并不坏,并且要小心使用
autouse
,因为它使测试更难阅读和调试。test function header中的显式fixture至少为您提供了一些查找已执行代码的指导。

为此,我更喜欢使用上下文管理器:

从contextlib导入contextmanager
@上下文管理器
使用()后必须清洁的def目录:
directory=set()
收益目录
不断言目录
def test_foo():
在使用()作为目录之后,目录必须是干净的:
directory.add(“文件”)
如果您绝对负担不起为每个测试添加这一行,那么将其作为插件编写就足够简单了

将其放入您的
conftest.py

导入pytest
directory=set()
#注册标记,以便pytest不会警告您未知标记
def pytest_配置(配置):
config.addinivalue\u行(“标记”,
“目录\u必须\u干净\u测试后:名称说明一切”)
#这将在每次测试中运行
@pytest.hookimpl(hookwrapper=True)
def pytest_运行测试_调用(项目):
directory.clear()
产量
if item.get_nexist_标记(“目录在测试后必须是干净的”):
不断言目录
并根据您的测试添加相应的标记:

#test.py
导入pytest
从conftest导入目录
def test_foo():
directory.add(“foo文件”)
@pytest.mark.directory\u必须在\u测试后\u干净\u
def测试条():
目录。添加(“bar文件”)
运行此命令将为您提供:

fail.py::test_foo PASSED
fail.py::test_bar FAILED
...
>           assert not directory
E           AssertionError: assert not {'bar file'}

conftest.py:13: AssertionError

当然,您不必使用标记,但它们允许控制插件的范围。您可以为每个类或每个模块设置标记。

我想这回答了问题,但我真正想知道的是,是否有一种方法可以自动将前置和/或后置条件应用于测试套件中的某些或所有测试。从表面上看,
autouse
fixture似乎可以用于此目的,但您已经指出,情况并非如此。也许我应该提出另一个更好的问题。在pytest中?没有我知道的,没有。再一次,即使你可以,我也会问你是否应该(尽管原因与我在回答中所说的不同)。您希望重复声明的这些条件是什么?实际用例是用于检测在任何特定测试结束后是否有任何文件句柄保持打开状态的插件。目前,当发现打开的文件时,我们被迫简单地导致错误,因为
pytest
似乎没有提供一种机制,其行为与我所描述的一样。例如,由测试打开的文件句柄?也就是说,您是否在尝试确保测试在完成后正确地清理?如果