如何配置 pytest 以避免丢失导入时收集失败?

sor*_*rin 8 python pytest

我确实有一些更复杂的项目,如果您运行pytest --collect-only这些项目,您最终会因发现的测试文件导入尚未安装的内容而导致大量导入失败。

我想以这样的方式更改这些测试文件,以免它们在收集时失败。

这是因为用户可能希望使用特定模式(如 )运行测试pytest -k foo,但如果在不相关的测试中收集失败,他将无法执行此操作。

我知道我可以定义一个pytest_configure称为 durind 集合的方法,但是如果我将导入移动到其中,当解释器到达尝试使用丢失的导入的代码时,我仍然会失败。

def pytest_configure(config):
    try:
        import foo
    except:
        pytest.skip("skipping when foo is not installed")

def test_foo()
  assert foo.is_enabled()  # <-- foo is undefined here

Run Code Online (Sandbox Code Playgroud)

我的示例显然过于简化了,因为我们都知道我可以在测试方法中再次添加导入,但我不想在数十种方法中这样做。我正在寻找更清洁的解决方案。

hoe*_*ing 16

如果您不想在导入(或任何其他)错误时中止测试收集,请使用该--continue-on-collection-errors标志。例子:

test_spam.py有一个未解决的导入:

import foo


def test_foo():
    assert foo.is_enabled()
Run Code Online (Sandbox Code Playgroud)

test_eggs.py可以运行:

def test_bar():
    assert True
Run Code Online (Sandbox Code Playgroud)

运行测试会产生:

$ pytest --continue-on-collection-errors -v
======================================= test session starts =======================================
...
collected 1 item / 1 errors                                                                       

test_eggs.py::test_bar PASSED

============================================= ERRORS ==============================================
__________________________________ ERROR collecting test_spam.py __________________________________
ImportError while importing test module '/home/hoefling/projects/private/stackoverflow/so-56997157/test_spam.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_spam.py:2: in <module>
    import foo
E   ModuleNotFoundError: No module named 'foo'
================================ 1 passed, 1 error in 0.06 seconds ================================
Run Code Online (Sandbox Code Playgroud)

这将指示pytest运行它可以收集的所有测试(test_eggs::test_bar在本例中),但由于无法收集一个模块而导致执行失败。如果你不想测试运行失败,pytest提供一个方便的importorskip功能:

import pytest
foo = pytest.importorskip('foo')


def test_foo():
    assert foo.is_enabled()
Run Code Online (Sandbox Code Playgroud)

现在运行测试会产生:

$ pytest -v
======================================= test session starts =======================================
...
collected 1 item / 1 skipped                                                                      

test_eggs.py::test_bar PASSED                                                               [100%]

=============================== 1 passed, 1 skipped in 0.04 seconds ===============================
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这两者之间的区别在于收集错误的处理 ( 1 errorsvs 1 skipped) 和生成的退出代码 (1 vs 0)。


就我个人而言,我倾向于不使用,importorskip因为从长远来看它可能导致测试无法执行。如果您有一个大型测试套件,通常您只需简要查看测试结果(失败/未失败),而不会明确检查是否有新的跳过测试。这可能会导致这样的情况:测试不会在任何地方执行(甚至不在 CI 服务器上),直到有人注意到它(最好的情况),或者(最坏的情况)假设要测试的代码在生产系统上发现错误。当然,还有其他可用的指标可以间接保护这种情况(例如注意测试覆盖率并禁止降低测试覆盖率的提交),但在我看来,明确的失败会设置一个巨大的感叹号,您无法避免。

来源:跳过缺少的导入依赖项