Заставьте охват только считать успешные тесты и игнорируйте тесты xfailing
У меня есть ряд проектов, где я использую 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%
Как вы можете видеть, все пять строк покрыты, но строки 3 и 4 попадают только во время xfail
тестовое задание.
То, как я справляюсь с этим сейчас, это настроить tox
запустить что-то вроде pytest -m "not xfail" --cov && pytest -m xfail
, но в дополнение к тому, чтобы быть немного громоздким, это только отфильтровывает вещи с xfail
mark, что означает, что условные xfails также отфильтровываются независимо от того, выполняется ли условие.
Есть ли способ иметь coverage
или же pytest
не рассчитывать покрытие от неудачных тестов? Кроме того, я был бы в порядке с механизмом игнорировать освещение от xfail
тесты, которые игнорируют только условные xfail
проверяет, выполняется ли условие
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/stackru, 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)