使覆盖仅计算成功的测试并忽略 xfailing 测试
Make coverage only count successful tests and ignore xfailing tests
我在许多项目中使用 pytest.mark.xfail
标记来标记失败但 不应 失败的测试,以便可以添加失败的测试用例在问题解决之前。我不想 跳过 这些测试,因为如果我做的某些事情导致它们开始通过,我想知道这一点,以便我可以删除 xfail
标记以避免倒退。
问题是因为 xfail
测试实际上 运行 直到失败,任何导致失败的行都被计为 "covered", 即使它们是未通过测试 的一部分,这给了我关于我的代码实际测试工作的多少的误导性指标。一个最小的例子是:
pkg.py
def f(fail):
if fail:
print("This line should not be covered")
return "wrong answer"
return "right answer"
test_pkg.py
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
标记,这意味着 条件 xfails 也会被过滤掉,无论是否满足条件。
有什么方法可以让 coverage
或 pytest
不计算失败测试的覆盖率?或者,我可以使用一种机制来忽略 xfail
测试的覆盖范围,如果满足条件,则只忽略条件 xfail
测试。
由于您使用的是 pytest-cov
插件,请利用其 no_cover
标记。当注释为 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/Whosebug, 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)
我在许多项目中使用 pytest.mark.xfail
标记来标记失败但 不应 失败的测试,以便可以添加失败的测试用例在问题解决之前。我不想 跳过 这些测试,因为如果我做的某些事情导致它们开始通过,我想知道这一点,以便我可以删除 xfail
标记以避免倒退。
问题是因为 xfail
测试实际上 运行 直到失败,任何导致失败的行都被计为 "covered", 即使它们是未通过测试 的一部分,这给了我关于我的代码实际测试工作的多少的误导性指标。一个最小的例子是:
pkg.py
def f(fail):
if fail:
print("This line should not be covered")
return "wrong answer"
return "right answer"
test_pkg.py
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
标记,这意味着 条件 xfails 也会被过滤掉,无论是否满足条件。
有什么方法可以让 coverage
或 pytest
不计算失败测试的覆盖率?或者,我可以使用一种机制来忽略 xfail
测试的覆盖范围,如果满足条件,则只忽略条件 xfail
测试。
由于您使用的是 pytest-cov
插件,请利用其 no_cover
标记。当注释为 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/Whosebug, 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)