Заставьте охват только считать успешные тесты и игнорируйте тесты xfailing - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть несколько проектов, в которых я использую маркер 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, что означает, что условные xfails также отфильтровываются, независимо от того, выполняется ли условие.

Есть ли способ, чтобы coverage или pytest не считали покрытие от неудачных тестов? В качестве альтернативы я был бы в порядке с механизмом игнорирования покрытия из xfail тестов, который игнорирует только условные xfail тесты, если условие выполнено.

1 Ответ

0 голосов
/ 08 ноября 2018

Поскольку вы используете плагин 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.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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...