Как правильно использовать extension.py в Python?

Я только начал использовать модуль Coverage.py и решил сделать простой тест, чтобы проверить, как это работает.

Sample.py

def sum(num1, num2):
    return num1 + num2


def sum_only_positive(num1, num2):
    if num1 > 0 and num2 > 0:
        return num1 + num2
    else:
        return None

test.py

from sample import sum, sum_only_positive

def test_sum():
    assert sum(5, 5) == 10

def test_sum_positive_ok():
    assert sum_only_positive(2, 2) == 4

def test_sum_positive_fail():
    assert sum_only_positive(-1, 2) is None

Как видите, весь мой код покрыт тестами, и py.test говорит, что все они проходят. Я ожидаю, что Coverage.py покажет 100% покрытие. Ну нет.

Coverage.py results

Что ж, Coverage.py может не видеть файл test.py, поэтому я скопировал тестовые функции в sample.py файл и снова запустил Coverage:
введите описание изображения здесь

Затем я добавил этот блок кода:

if __name__ == "__main__":
    print(sum(2, 4))
    print(sum_only_positive(2, 4))
    print(sum_only_positive(-1, 3))

и удалили все тестовые функции. После этого Coverage.py показывает 100%:

введите описание изображения здесь

Почему это так? Разве Coverage.py не должен показывать покрытие тестирования кода, а не только выполнение? Я прочитал официальный FAQ по Coverage.py, но не могу найти решение.
Поскольку многие пользователи SO знакомы с тестированием кода и покрытием кода, я надеюсь, что вы скажете мне, где я ошибаюсь.

У меня есть только одна мысль: Coverage.py может просто наблюдать, какие строки кода не выполняются, поэтому я должен написать тесты для этих строк. Но есть строки, которые уже выполняются, но не покрыты тестами, поэтому Coverage.py здесь не сработает.


person Groosha    schedule 09.04.2016    source источник
comment
Как вы вызываете покрытие / pytest?   -  person Łukasz Rogalski    schedule 09.04.2016
comment
@Rogalski pytest: python -m py.test test.py и охват: python -m coverage run sample.py (в Windows)   -  person Groosha    schedule 09.04.2016
comment
он не показывает 100%, он показывает те же строки, что и не покрытый ... у меня все еще не работает. Я скопировал вставленный ваш код и убедился, что у меня есть py.test и cover.py с pip. Я вижу то же самое в командной строке и в intellij, пожалуйста, LMK.   -  person Nirmal    schedule 05.04.2019


Ответы (3)


Coverage ищет файл с расширением .coverage, чтобы прочитать и создать для вас этот отчет. Py.test сам по себе не создает его. Вам понадобится плагин py.test для покрытия:

pip install pytest-cov

Если он у вас уже есть, вы можете запустить оба сразу следующим образом:

py.test test.py --cov=sample.py

Это означает запуск модуля тестирования test.py и запись / отображение отчета о покрытии на sample.py.

Если вам нужно провести несколько тестовых прогонов и накопить их записанное покрытие, а затем отобразить окончательный отчет, вы можете запустить его следующим образом:

py.test test.py --cov=sample.py --cov-report=
py.test test.py --cov=sample2.py --cov-report=
py.test test.py --cov=sample3.py --cov-report=

Это означает, что запустить тестовый модуль test.py и записать (только) покрытие на sample.py - не отображать отчет.

Теперь вы можете запускать команду покрытия отдельно для получения полного отчета:

coverage report -m

Приведенная выше команда просто отображает отформатированный отчет о покрытии, основанный на накопленном файле данных .coverage из предыдущих тестовых запусков. -m означает пропущенные строки, т.е. строки, не охваченные тестами:

Name        Stmts   Miss  Cover   Missing
-----------------------------------------
sample.py       6      0   100%  

Покрытие поддерживает больше переключателей, таких как --include и --omit, для включения / исключения файлов с использованием шаблонов путей. Для получения дополнительной информации ознакомьтесь с их документами: https://coverage.readthedocs.io/en/coverage-4.5.1/cmd.html#reporting.

person fips    schedule 09.04.2016
comment
Не работает, если проверяемый файл является подмодулем в пакете, который импортируется в тесте. Что бы я ни указывал в --cov=<> - только имя файла, относительный или абсолютный путь - я получаю ОШИБКА: не удалось создать отчет: нет данных для отчета. - person ivan_pozdeev; 02.11.2017
comment
asterisk / mydir / asterisk работает для опускания. Я бы написал * вместо звездочки, но она станет жирной. - person Squirrel; 31.01.2018
comment
Используйте --branch, чтобы также добавить покрытие ветки. - person danger89; 14.09.2018
comment
Вы также можете сделать что-то вроде coverage run --source=<module-name> -m pytest <test-location> вместо py.test test.py --cov=sample.py, если дополнительная зависимость того не стоит. - person Karuhanga; 16.10.2018
comment
Вам необходимо установить pytest-cov, который добавляет поддержку параметра --cov или, альтернативно, подход в комментарии выше также должен работать. - person fips; 19.12.2020

Проанализировать ваши эксперименты немного сложно, и вы не включили командные строки, которые использовали в каждом эксперименте. Но: если вы запустите тесты с:

python -m py.test test.py

тогда вы можете запустить их под покрытием .py с помощью:

coverage run -m py.test test.py
person Ned Batchelder    schedule 09.04.2016
comment
Кстати, я включил команды, используемые для запуска тестов и покрытия, прямо под моим сообщением во втором комментарии: pytest: python -m py.test test.py и охват: python -m coverage run sample.py (в Windows). Я вижу, что ваша вторая команда отличается от моей, проверю, спасибо! - person Groosha; 10.04.2016
comment
Возможно, проблема здесь в простом недоразумении: вы не должны запускать тесты, а затем покрытие. Вы должны использовать покрытие для запуска тестов (как я рекомендую) или включить покрытие во время выполнения тестов (например, с помощью подключаемого модуля покрытия для бегуна тестов). - person Ned Batchelder; 11.04.2016
comment
У меня не работает :( coverage -m - ›No such option -m. coverage run py.test test.py -› Unknown command py.test (py.test установлен) - person Groosha; 11.04.2016
comment
извините, опечатка, сейчас исправлена. - person Ned Batchelder; 11.04.2016
comment
@NedBatchelder Этот метод включает test.py в сгенерированный отчет. Считается ли это лучшей практикой при использовании такого инструмента, как покрытие? Под этим я подразумеваю намерение всегда измерять как покрытие тестируемого модуля, так и сам тест? Если нет, как мне исключить покрытие test.py из отчета? - person Grr; 16.03.2017
comment
Не вижу причин исключать тесты из измерений, а только плюсы. У вас есть код в ваших тестах, вы хотите знать, что он выполняется. Coverage.py может вам это сказать. - person Ned Batchelder; 17.03.2017

Следующая команда сработала для меня:

coverage run --source=sample -m pytest test.py

coverage report -m
person Anand    schedule 11.11.2020
comment
Внимание всем, кто сталкивается с этим вопросом. Начиная с версии 2021 и версии 5.3.1, это рекомендуемый способ. - person Jarmos; 07.01.2021