J'ai un script python qui prend des arguments en ligne de commande, travaille avec certains fichiers . J'écris les tests suivants avec py.test
en mettant ce script à l'épreuve, en l'exécutant avec subprocess.call
.
Maintenant, je veux analyser la couverture de code avec coverage.py
. Coverage, lorsqu'elle est utilisée via le plugin pytest-cov
(qui intègre la gestion des sous-processus), ne voit pas/couvre pas mon script lorsqu'il est appelé de manière temporaire. Répertoire de test créé avec la variable tmpdir
de py.test
. La couverture voit mon script lorsqu'il est appelé dans le répertoire où il réside (et l'argument du nom de fichier pointe vers un chemin distant).
Dans les deux situations, mes tests réussissent! Couverture 3.6, pytest-2.3.5, pytest-cov 1.6, tous issus de PyPi.
Question: Comment puis-je obtenir une couverture pour reconnaître mon script même s’il est exécuté dans un autre répertoire? Est-ce un bug dans la couverture, ou quelque chose qu'il est tout simplement impossible de faire? Serait surpris si ce dernier, après tout, tmpdir
est un mécanisme de stock de py.test ...
Exemple minimal:
J'ai un script my_script.py
qui reprend simplement le contenu d'un fichier arg_file.txt
fourni via un argument de ligne de commande. Dans deux tests différents, ceci est appelé une fois dans une tmpdir
et une fois à l'emplacement du script. Les deux tests réussissent, mais dans le test tmpdir, je n’obtiens aucune information sur la couverture!
Essai:
~/pytest_experiment$ py.test -s
=================================== test session starts ====================================
platform linux2 -- Python 2.7.4 -- pytest-2.3.5
plugins: cov
collected 2 items
tests/test_in_scriptdir.py
set_up: In directory /tmp/pytest-52/test_10
Running in directory /home/cbuchner/pytest_experiment
Command: ./my_script.py /tmp/pytest-52/test_10/arg_file.txt
--Contents of arg_file.txt--
.
tests/test_in_tmpdir.py
set_up: In directory /tmp/pytest-52/test_11
Running in directory /tmp/pytest-52/test_11
Command: /home/cbuchner/pytest_experiment/my_script.py arg_file.txt
--Contents of arg_file.txt--
.
================================= 2 passed in 0.06 seconds =================================
Couverture:
~/pytest_experiment$ py.test --cov=my_script.py tests/test_in_scriptdir.py=================================== test session starts ====================================
platform linux2 -- Python 2.7.4 -- pytest-2.3.5
plugins: cov
collected 1 items
tests/test_in_scriptdir.py .
--------------------- coverage: platform linux2, python 2.7.4-final-0 ----------------------
Name Stmts Miss Cover
-------------------------------
my_script 3 0 100%
================================= 1 passed in 0.09 seconds =================================
~/pytest_experiment$ py.test --cov=my_script.py tests/test_in_tmpdir.py=================================== test session starts ====================================
platform linux2 -- Python 2.7.4 -- pytest-2.3.5
plugins: cov
collected 1 items
tests/test_in_tmpdir.py .Coverage.py warning: No data was collected.
--------------------- coverage: platform linux2, python 2.7.4-final-0 ----------------------
Name Stmts Miss Cover
---------------------------
================================= 1 passed in 0.09 seconds =================================
Les fichiers sont ici: https://Gist.github.com/bilderbuchi/6412754
Edit: Il est intéressant de noter que lors de l'exécution des tests de couverture avec -s
, la sortie est plus curieuse: la couverture avertit que No data was collected
, lorsqu'elle a été collectée, et dans le test tmpdir
, prévient que Module my_script.py was never imported.
??
~/pytest_experiment$ py.test -s --cov=my_script.py tests/test_in_scriptdir.py
=================================== test session starts ====================================
platform linux2 -- Python 2.7.4 -- pytest-2.3.5
plugins: cov
collected 1 items
tests/test_in_scriptdir.py
set_up: In directory /tmp/pytest-63/test_10
Running in directory /home/cbuchner/pytest_experiment
Command: ./my_script.py /tmp/pytest-63/test_10/arg_file.txt
--Contents of arg_file.txt--
Coverage.py warning: No data was collected.
.
--------------------- coverage: platform linux2, python 2.7.4-final-0 ----------------------
Name Stmts Miss Cover
-------------------------------
my_script 3 0 100%
================================= 1 passed in 0.09 seconds =================================
~/pytest_experiment$ py.test -s --cov=my_script.py tests/test_in_tmpdir.py=================================== test session starts ====================================
platform linux2 -- Python 2.7.4 -- pytest-2.3.5
plugins: cov
collected 1 items
tests/test_in_tmpdir.py
set_up: In directory /tmp/pytest-64/test_10
Running in directory /tmp/pytest-64/test_10
Command: /home/cbuchner/pytest_experiment/my_script.py arg_file.txt
--Contents of arg_file.txt--
Coverage.py warning: Module my_script.py was never imported.
Coverage.py warning: No data was collected.
Coverage.py warning: Module my_script.py was never imported.
Coverage.py warning: No data was collected.
.Coverage.py warning: No data was collected.
--------------------- coverage: platform linux2, python 2.7.4-final-0 ----------------------
Name Stmts Miss Cover
---------------------------
================================= 1 passed in 0.09 seconds =================================
Il s’est avéré qu’il s’agissait d’un problème de couverture relative des chemins relatifs, lorsque le script mesuré est exécuté à partir d’un autre répertoire. Les fichiers de résultat de couverture se sont retrouvés dans ce répertoire, au lieu du répertoire racine du projet.
Pour résoudre ce problème, j'ai arrêté d'utiliser pytest-cov
et utilisé pure coverage
à la place. J'ai utilisé des chemins complets au lieu de chemins relatifs, le cas échéant.
Donc, par exemple définit la variable d'environnement nécessaire pour activer la couverture de sous-processus via export COVERAGE_PROCESS_START=/full/path/to/.coveragerc
. Dans le .coveragerc
, le fichier de résultat de la couverture est spécifié via
[run]
data_file = /full/path/to/.coverage
et toutes les options --source
et --include
doivent également utiliser des chemins complets .. .. Il était alors possible d'obtenir une mesure de couverture correcte.
J'ai rencontré le même problème lorsque j'ai appelé "py.test --cov ..." de tox. J'ai trouvé un indice sur cette page: http://blog.ionelmc.ro/2014/05/25/python-packaging/ même s'il ne le mentionne pas explicitement. L'utilisation de "--develop" pour tox garantira que la collecte des données de couverture est appelée depuis le même répertoire que l'analyse de couverture . Cette section de tox.ini m'a permis de disposer d'un environnement de test de la couverture. :
[tox]
envlist = ...,py34,cov
[testenv:cov]
# necessary to make cov find the .coverage file
# see http://blog.ionelmc.ro/2014/05/25/python-packaging/
usedevelop = true
commands = py.test --cov=<MODULE_NAME>
deps = pytest pytest-cov
Une autre option avec tox est de définir la PYTHONPATH
dans tox.ini
:
[testenv]
setenv =
PYTHONPATH = {toxinidir}
commands =
pytest --cov=<your package>
- codecov