Используя py.тест с покрытием не включает импорт


Для джедаев мы хотим создать наше тестовое покрытие. В stackoverflow естьсвязанный вопрос , но это не помогло.

Мы используем py.тест в качестве тестового бегуна. Однако мы не можем добавить импорт и другие "импортные" материалы в отчет. Например, __init__.py всегда сообщается как раскрытое:

Name                           Stmts   Miss  Cover
--------------------------------------------------
jedi/__init__                      5      5     0%
[..]

Очевидно, что этот файл импортируется и поэтому должен быть зарегистрирован как проверенный.

Мы начинаем тесты так: [*]:

py.test --cov jedi
Как вы можете видеть, мы используем pytest-coverage.

Итак, как можно правильно подсчитать охват файлов, таких как __init__.py?

[*] мы также попытались запустить тест без --doctest-modules (удалено из pytest.ini) и активировать модуль покрытия ранее по py.test -p pytest_cov --cov jedi. Ни один из них не работает.

Я предложил награду. Пожалуйста, попытайтесь исправить это в джедае. Он находится в открытом доступе.

4 35

4 ответа:

@hynekcer подал мне правильную идею. Но в принципе самое простое решение лежит где-то в другом месте:

Избавьтесь от pytest-cov!

Использовать

coverage run --source jedi -m py.test
coverage report

Вместо этого!!! Таким образом, вы просто запускаете покрытие на вашем текущем py.Тестовая конфигурация, которая отлично работает! Это также философски правильный путь: заставить каждую программу делать одну вещь хорошо - py.test запускает тесты и coverage проверяет покрытие кода.

Сейчас это может звучать как напыщенная речь, но на самом деле. pytest-cov не имеет я уже некоторое время нормально работаю. Некоторые тесты проваливались только потому, что мы их использовали.

По состоянию на 2014, питест-ков, похоже, перешел из рук в руки. py.test --cov jedi test снова кажется полезной командой (посмотрите на комментарии). Однако вам не нужно его использовать. Но в сочетании с xdist это может ускорить ваши отчеты о покрытии.

Я исправил тестовое покрытие до 94% с помощью этого патча, который упрощает импорт зависимостей, и командой:

py.test --cov jedi test                    # or
py.test --cov jedi test --cov-report=html  # + a listing with red uncovered lines

Открытые строки находятся только в условных командах или в некоторых менее используемых функциях, но все заголовки полностью закрыты.

Проблема заключалась в том, что конфигурация тестов test/conftest.py преждевременно импортировала по зависимостям почти все файлы в проекте. Файл conftest определяет также дополнительные параметры командной строки и параметры, которые должны быть установлены перед запуском теста. Поэтому я думаю, что плагин pytest_cov работает правильно, если он игнорирует все, что было импортировано вместе с этим файлом, хотя это и боль. Я исключил также __init__.py и settings.py из отчета, потому что они просты и с полным охватом, но они также были импортированы преждевременно в зависимости от conftest.

В моем случае все тесты выполнены, но охват составил 0%.

Исправление было:

$ export PYTHONPATH="."

После того, как результаты были правильными.

В прошлом у меня было несколько проблем с командой py.test, у которой были проблемы с импортом чего-то, и установка PYTHONPATH env var была решением. Это сработало и на этот раз.

Мой реальный пример с awslogs

Сначала с PYTHONPATH unset:

$ py.test --cov=awslogs  tests/
========================================= test session starts =========================================
platform linux2 -- Python 2.7.9, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: /home/javl/sandbox/awslogs/github/awslogs, inifile:
plugins: cov-2.2.0
collected 11 items

tests/test_it.py ...........Coverage.py warning: No data was collected.

--------------------------- coverage: platform linux2, python 2.7.9-final-0 ---------------------------
Name                    Stmts   Miss  Cover
-------------------------------------------
awslogs/__init__.py         2      2     0%
awslogs/bin.py             85     85     0%
awslogs/core.py           143    143     0%
awslogs/exceptions.py      12     12     0%
-------------------------------------------
TOTAL                     242    242     0%

====================================== 11 passed in 0.38 seconds ======================================

Результирующее покрытие составляет 0%.

Затем я задаю PYTHONPATH:

$ export PYTHONPATH="."

И повторите тест:

$ py.test --cov=awslogs  tests/
========================================= test session starts =========================================
platform linux2 -- Python 2.7.9, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: /home/javl/sandbox/awslogs/github/awslogs, inifile:
plugins: cov-2.2.0
collected 11 items

tests/test_it.py ...........
--------------------------- coverage: platform linux2, python 2.7.9-final-0 ---------------------------
Name                    Stmts   Miss  Cover
-------------------------------------------
awslogs/__init__.py         2      0   100%
awslogs/bin.py             85      9    89%
awslogs/core.py           143     12    92%
awslogs/exceptions.py      12      2    83%
-------------------------------------------
TOTAL                     242     23    90%

====================================== 11 passed in 0.44 seconds ======================================

Сейчас охват составляет 90%.

Предупреждение : манипулирование PYTHONPATH может иметь странные побочные эффекты. В настоящее время я сталкиваюсь с проблемой, что пакет на основе pbr создает каталог egg при построении distributable и если PYTHONPATH установлен в ".", он автоматически считает пакет, связанный с яйцом, установленным. По этой причине я перестал использовать pytest-cov и следую совету использовать вместо этого инструмент coverage.

У меня была такая проблема с py.тест, покрытие и плагин django. Очевидно, файлы модели импортируются до начала покрытия. Даже "- P покрытие " для ранней загрузки покрытия-плагин не работал.

Я починил его (уродливый?) путем удаления модуля models из sys.модули и повторный импорт его в тестовый файл, который тестирует модель:

import sys
del sys.modules['project.my_app.models']
from project.my_app import models

def test_my_model():
  ...