web-dev-qa-db-fra.com

couverture.py ne couvre pas le script si py.test l'exécute depuis un autre répertoire

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 =================================
30
Christoph

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.

6
Christoph

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
15
okurz

Une autre option avec tox est de définir la PYTHONPATH dans tox.ini:

[testenv] setenv = PYTHONPATH = {toxinidir} commands = pytest --cov=<your package> - codecov

0
Midnighter