python - tests - Exécution d'unittest avec une structure de répertoire de test typique




run python tests (10)

La structure de répertoires très commune même pour un simple module Python semble être de séparer les tests unitaires dans leur propre répertoire de test :

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py
    setup.py
    etc.

par exemple voir ce howto de projet Python .

Ma question est simplement Quelle est la façon habituelle de faire les tests? Je suppose que cela est évident pour tout le monde sauf moi, mais vous ne pouvez pas exécuter python test_antigravity.py partir du répertoire de test car son import antigravity échouera car le module n'est pas sur le chemin.

Je sais que je pourrais modifier PYTHONPATH et d'autres trucs liés au chemin de recherche, mais je ne peux pas croire que c'est le moyen le plus simple - c'est bien si vous êtes le développeur mais pas réaliste d'attendre vos utilisateurs qui passe.

L'autre alternative est juste de copier le fichier de test dans l'autre répertoire, mais il semble un peu bête et manque le point de les avoir dans un répertoire séparé pour commencer.

Donc, si vous aviez juste téléchargé la source de mon nouveau projet, comment exécuteriez-vous les tests unitaires? Je préférerais une réponse qui me permettrait de dire à mes utilisateurs: "Pour exécuter les tests unitaires, faites X."


Quelle est la manière habituelle d'exécuter les tests?

J'utilise Python 3.6.2

cd new_project

pytest test/test_antigravity.py

Pour installer pytest : sudo pip install pytest

Je n'ai défini aucune variable de chemin et mes importations n'échouent pas avec la même structure de projet "test".

J'ai commenté ce truc: if __name__ == '__main__' comme ceci:

test_antigravity.py

import antigravity

class TestAntigravity(unittest.TestCase):

    def test_something(self):

        # ... test stuff here


# if __name__ == '__main__':
# 
#     if __package__ is None:
# 
#         import something
#         sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
#         from .. import antigravity
# 
#     else:
# 
#         from .. import antigravity
# 
#     unittest.main()

De l'article que vous avez lié à:

Créez un fichier test_modulename.py et placez-y vos tests unittest. Comme les modules de test se trouvent dans un répertoire distinct de votre code, vous devrez peut-être ajouter le répertoire parent de votre module à votre PYTHONPATH pour les exécuter:

$ cd /path/to/googlemaps

$ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps

$ python test/test_googlemaps.py

Enfin, il existe un framework de test unitaire plus populaire pour Python (c'est si important!), Nez. nose permet de simplifier et d'étendre le framework unittest intégré (il peut, par exemple, trouver automagiquement votre code de test et configurer votre PYTHONPATH pour vous), mais il n'est pas inclus dans la distribution Python standard.

Peut-être devriez-vous regarder le nose comme il le suggère?


J'ai eu le même problème, avec un dossier de tests unitaires séparé. À partir des suggestions mentionnées, j'ajoute le chemin source absolu à sys.path .

L'avantage de la solution suivante est que l'on peut exécuter le fichier test/test_yourmodule.py sans changer d'abord dans le répertoire de test:

import sys, os
testdir = os.path.dirname(__file__)
srcdir = '../src/projekt/dir'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))

import yourmodule
import unittest

J'ai remarqué que si vous exécutez l'interface de ligne de commande unittest à partir de votre répertoire "src", les importations fonctionnent correctement sans modification.

python -m unittest discover -s ../test

Si vous voulez mettre cela dans un fichier batch dans votre répertoire de projet, vous pouvez le faire:

setlocal & cd src & python -m unittest discover -s ../test

La meilleure solution à mon avis est d'utiliser l' interface de ligne de commande unittest qui ajoutera le répertoire à sys.path afin que vous n'ayez pas à le faire (fait dans la classe TestLoader ).

Par exemple pour une structure de répertoire comme ceci:

new_project
├── antigravity.py
└── test_antigravity.py

Vous pouvez simplement lancer:

$ cd new_project
$ python -m unittest test_antigravity

Pour une structure de répertoire comme la tienne:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

Et dans les modules de test à l'intérieur du package de test , vous pouvez importer le package antigravity et ses modules comme d'habitude:

# import the package
import antigravity

# import the antigravity module
from antigravity import antigravity

# or an object inside the antigravity module
from antigravity.antigravity import my_object

Exécuter un seul module de test:

Pour exécuter un seul module de test, dans ce cas test_antigravity.py :

$ cd new_project
$ python -m unittest test.test_antigravity

Référencez simplement le module de test de la même manière que vous l'importez.

Exécution d'un seul cas de test ou méthode de test:

Vous pouvez également exécuter un seul TestCase ou une seule méthode de test:

$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method

Exécuter tous les tests:

Vous pouvez également utiliser la découverte de test qui va découvrir et exécuter tous les tests pour vous, il doit s'agir de modules ou de paquets nommés test*.py (peut être modifié avec l' -p, --pattern ):

$ cd new_project
$ python -m unittest discover

Cela exécutera tous les modules de test*.py à l'intérieur du package de test .


La solution la plus simple pour vos utilisateurs est de fournir un script exécutable ( runtests.py ou autre) qui amorce l'environnement de test nécessaire, y compris, si nécessaire, l'ajout temporaire de votre répertoire de projet racine à sys.path. Cela ne nécessite pas de définir des variables d'environnement, ce qui fonctionne très bien dans un script bootstrap:

import sys, os

sys.path.insert(0, os.path.dirname(__file__))

Ensuite, vos instructions à vos utilisateurs peuvent être aussi simples que "python runtests.py".

Bien sûr, si le chemin dont vous avez réellement besoin est os.path.dirname(__file__) , vous n'avez pas besoin de l'ajouter à sys.path ; Python place toujours le répertoire du script en cours au début de sys.path , donc en fonction de la structure de votre répertoire, il suffit de localiser votre runtests.py au bon endroit.

De plus, le module unittest dans Python 2.7+ (qui est rétroporté comme unittest2 pour Python 2.6 et versions antérieures) a maintenant une détection de test intégrée, donc le nose n'est plus nécessaire si vous voulez une découverte de test automatique: vos instructions d'utilisateur peuvent être aussi simples que "python -m unittest decouvre".


Si vous utilisez VS Code et que vos tests sont situés au même niveau que votre projet, l'exécution et le débogage de votre code ne fonctionnent pas immédiatement. Ce que vous pouvez faire est de changer votre fichier launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "program": "${file}",
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.env",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }    
    ]
}

La ligne clé ici est envFile

"envFile": "${workspaceRoot}/.env",

A la racine de votre projet, ajoutez le fichier .env

À l'intérieur de votre fichier .env, ajoutez le chemin à la racine de votre projet. Cela ajoutera temporairement

PYTHONPATH = C: \ VOTRE \ PYTHON \ PROJECT \ ROOT_DIRECTORY

chemin vers votre projet et vous serez en mesure d'utiliser les tests unitaires de débogage de VS Code


Utilisez setup.py develop pour que votre répertoire de travail fasse partie de l'environnement Python installé, puis exécutez les tests.


Vous devriez vraiment utiliser l'outil pip.

Utilisez pip install -e pour installer votre paquet en mode développement. C'est une très bonne pratique.

Dans l'URL de référence ci-dessous, 2 projets classiques (avec test) sont donnés, vous pouvez les suivre.

Ref :


Solution / Exemple pour Python unittest module

Compte tenu de la structure de projet suivante:

ProjectName
 ├── project_name
 |    ├── models
 |    |    └── thing_1.py
 |    └── __main__.py
 └── test
      ├── models
      |    └── test_thing_1.py
      └── __main__.py

Vous pouvez exécuter votre projet à partir du répertoire racine avec python project_name , qui appelle ProjectName/project_name/__main__.py .

Pour exécuter vos tests avec le python test , en exécutant ProjectName/test/__main__.py , vous devez effectuer les opérations suivantes:

1) Transformez votre répertoire test/models en package en ajoutant un fichier __init__.py . Cela rend les cas de test dans le sous-répertoire accessibles à partir du répertoire de test parent.

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2) Modifiez le chemin d'accès de votre système dans test/__main__.py pour inclure le répertoire project_name .

# ProjectName/test/__main__.py

import sys
import unittest

sys.path.append('../project_name')

loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)

Vous pouvez maintenant importer des objets de project_name dans vos tests.

# ProjectName/test/models/test_thing_1.py    

import unittest
from project_name.models import Thing1  # this doesn't work without 'sys.path.append' per step 2 above

class Thing1TestCase(unittest.TestCase):

    def test_thing_1_init(self):
        thing_id = 'ABC'
        thing1 = Thing1(thing_id)
        self.assertEqual(thing_id, thing.id)






unit-testing