Python 使覆盖率只计算成功的测试,而忽略失败的测试
我有许多项目使用Python 使覆盖率只计算成功的测试,而忽略失败的测试,python,pytest,coverage.py,pytest-cov,Python,Pytest,Coverage.py,Pytest Cov,我有许多项目使用pytest.mark.xfail标记失败但不应该失败的测试,以便在修复问题之前添加失败的测试用例。我不想跳过这些测试,因为如果我做的事情导致他们开始通过测试,我希望得到通知,这样我就可以删除xfail标记以避免回归 问题在于,因为xfail测试实际上一直运行到失败为止,所以导致失败的任何行都被视为“已覆盖”,即使它们是未通过测试的一部分,这就给了我关于有多少代码实际被测试为正常工作的误导性指标。一个最简单的例子是: pkg.py def f(fail): if fail
pytest.mark.xfail
标记失败但不应该失败的测试,以便在修复问题之前添加失败的测试用例。我不想跳过这些测试,因为如果我做的事情导致他们开始通过测试,我希望得到通知,这样我就可以删除xfail
标记以避免回归
问题在于,因为xfail
测试实际上一直运行到失败为止,所以导致失败的任何行都被视为“已覆盖”,即使它们是未通过测试的一部分,这就给了我关于有多少代码实际被测试为正常工作的误导性指标。一个最简单的例子是:
pkg.py
def f(fail):
if fail:
print("This line should not be covered")
return "wrong answer"
return "right answer"
import pytest
from pkg import f
def test_success():
assert f(fail=False) == "right answer"
@pytest.mark.xfail
def test_failure():
assert f(fail=True) == "right answer"
test_pkg.py
def f(fail):
if fail:
print("This line should not be covered")
return "wrong answer"
return "right answer"
import pytest
from pkg import f
def test_success():
assert f(fail=False) == "right answer"
@pytest.mark.xfail
def test_failure():
assert f(fail=True) == "right answer"
运行python-m pytest--cov=pkg,我得到:
platform linux -- Python 3.7.1, pytest-3.10.0, py-1.7.0, pluggy-0.8.0
rootdir: /tmp/cov, inifile:
plugins: cov-2.6.0
collected 2 items
tests/test_pkg.py .x [100%]
----------- coverage: platform linux, python 3.7.1-final-0 -----------
Name Stmts Miss Cover
----------------------------
pkg.py 5 0 100%
正如您所看到的,所有五行都被覆盖,但是第3行和第4行仅在xfail
测试期间被命中
我现在处理这个问题的方法是设置tox
来运行类似pytest-m“not xfail”-cov&&pytest-m xfail
,但是除了有点麻烦之外,这只是用xfail
标记过滤掉一些东西,这意味着条件xfail也会被过滤掉,无论是否满足条件
有没有办法让
coverage
或pytest
不计算失败测试的覆盖率?或者,我也可以使用一种忽略xfail
测试覆盖率的机制,该机制仅在满足条件的情况下忽略条件xfail
测试。因为您使用的是pytest-cov
插件,请利用它的标记。当使用pytest.mark.no_cover
注释时,测试的代码覆盖率将关闭。唯一需要实现的就是将no_cover
标记应用于所有标记为pytest.mark.xfail
的测试。在您的conftest.py
中:
import pytest
def pytest_collection_modifyitems(items):
for item in items:
if item.get_closest_marker('xfail'):
item.add_marker(pytest.mark.no_cover)
现在运行您的示例将产生:
$ pytest --cov=pkg -v
=================================== test session starts ===================================
platform darwin -- Python 3.7.1, pytest-3.9.1, py-1.7.0, pluggy-0.8.0
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow, inifile:
plugins: cov-2.6.0
collected 2 items
test_pkg.py::test_success PASSED [ 50%]
test_pkg.py::test_failure xfail [100%]
---------- coverage: platform darwin, python 3.7.1-final-0 -----------
Name Stmts Miss Cover
----------------------------
pkg.py 5 2 60%
=========================== 1 passed, 1 xfailed in 0.04 seconds ===========================
编辑:处理xfail
标记中的条件
标记参数可以通过marker.args
和marker.kwargs
访问,因此如果您有一个标记
@pytest.mark.xfail(sys.platform == 'win32', reason='This fails on Windows')
使用访问参数
marker = item.get_closest_marker('xfail')
condition = marker.args[0]
reason = marker.kwargs['reason']
考虑条件标志,上面的钩子可以修改如下:
def pytest_collection_modifyitems(items):
for item in items:
marker = item.get_closest_marker('xfail')
if marker and (not marker.args or marker.args[0]):
item.add_marker(pytest.mark.no_cover)
这似乎是解决方案的一半;仅当满足故障条件时,有条件的X故障测试还需要关闭覆盖率。不过,我认为这可能解决了问题中最难的部分。哦,您希望对带有
xfail
结果的测试关闭覆盖率(例如,对于带有xpass
结果的测试关闭覆盖率)?测试完成后覆盖率结果的后处理方式?不,xfail
采用布尔值,因此可以表示“这在Windows上失败”。我总是使用默认为strict的xfail
运行,但根据我的经验,无论bool是否为true,测试都会得到xfail
标记;条件标志是标记参数中的第一个属性,因此不难将其考虑在内。我用一个例子更新了答案。这是一个非常有趣的想法!在coverage 5.0 alpha中,我们可以跟踪哪些测试覆盖了哪些行。如果我们使用pytest插件来帮助实现这一点,也许它可以禁用xfail测试的测量功能。您介意将此作为一个问题写在coverage.py repo上吗@内德:我会的。