使覆盖率仅计算成功的测试,而忽略xfailing测试

时间:2018-11-07 14:53:32

标签: python pytest coverage.py pytest-cov

我有多个项目,在这些项目中我使用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"

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%

如您所见,所有五行都被覆盖,但是仅在xfail测试期间命中了行3和4。

我现在处理此问题的方法是设置tox来运行类似pytest -m "not xfail" --cov && pytest -m xfail的内容,但是除了有点麻烦之外,这还只是用xfail过滤掉了某些内容标记,这意味着有条件的 xfails也会被滤除,无论是否满足条件。

有什么方法可以使coveragepytest不计入测试失败的覆盖率?另外,我可以采用一种机制来忽略xfail测试中的覆盖率,该机制仅在满足条件时才忽略条件xfail测试。

1 个答案:

答案 0 :(得分:1)

由于您使用的是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/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.argsmarker.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)