Exécution d'un cas de test spécifique dans Django lorsque votre application dispose d'un répertoire de tests


165

La documentation Django ( http://docs.djangoproject.com/en/1.3/topics/testing/#running-tests ) indique que vous pouvez exécuter des cas de test individuels en les spécifiant:

$ ./manage.py test animals.AnimalTestCase

Cela suppose que vous ayez vos tests dans un fichier tests.py dans votre application Django. Si cela est vrai, cette commande fonctionne comme prévu.

J'ai mes tests pour une application Django dans un répertoire de tests:

my_project/apps/my_app/
├── __init__.py
├── tests
   ├── __init__.py
   ├── field_tests.py
   ├── storage_tests.py
├── urls.py
├── utils.py
└── views.py

Le tests/__init__.pyfichier a une fonction suite ():

import unittest

from my_project.apps.my_app.tests import field_tests, storage_tests

def suite():
    tests_loader = unittest.TestLoader().loadTestsFromModule
    test_suites = []
    test_suites.append(tests_loader(field_tests))
    test_suites.append(tests_loader(storage_tests))
    return unittest.TestSuite(test_suites)

Pour exécuter les tests que je fais:

$ ./manage.py test my_app

Essayer de spécifier un cas de test individuel déclenche une exception:

$ ./manage.py test my_app.tests.storage_tests.StorageTestCase
...
ValueError: Test label 'my_app.tests.storage_tests.StorageTestCase' should be of the form app.TestCase or app.TestCase.test_method

J'ai essayé de faire ce que le message d'exception disait:

$ ./manage.py test my_app.StorageTestCase
...
ValueError: Test label 'my_app.StorageTestCase' does not refer to a test

Comment spécifier un cas de test individuel lorsque mes tests sont dans plusieurs fichiers?

Réponses:


156

Commander django-nose . Il vous permet de spécifier des tests à exécuter comme:

python manage.py test another.test:TestCase.test_method

ou comme indiqué dans les commentaires, utilisez la syntaxe:

python manage.py test another.test.TestCase.test_method

Merci @sdolan. Rencontré le même problème que hekevintran. Passé à django-nose et a corrigé ce problème, fonctionne également beaucoup mieux que le testeur par défaut de Django.
LeeMobile

Cela exécute un test, mais comment exécuter un TestCase entier?
jMyles

5
@jMyles:another.test:TestCase
Sam Dolan

4
Attention les gens comme moi qui collent aveuglément à partir de Stackoverflow: Cela fera une erreur sans le plugin mentionné, utilisez la syntaxe décrite dans l'autre réponse (. Au lieu de :) qui fonctionne dans Django 1.6+.
Andy Smith

1
J'ai décliné cette réponse car elle ne répond en fait pas à la question de l'OP, à savoir comment faire cela dans Django. Au contraire, cela suggère simplement de passer à Nosetest
Josh Brown

175

Depuis Django 1.6, vous pouvez exécuter un cas de test complet, ou un test unique, en utilisant la notation par points complète pour l'élément que vous souhaitez exécuter.

La découverte de test automatique trouvera désormais des tests dans tous les fichiers commençant par test sous le répertoire de travail.Pour répondre à la question, vous devrez renommer vos fichiers, mais vous pouvez maintenant les conserver dans le répertoire de votre choix. Si vous souhaitez utiliser des noms de fichiers personnalisés, vous pouvez spécifier un modèle (lanceur de test Django par défaut) avec l'option flag --pattern="my_pattern_*.py".

Donc, si vous êtes dans votre manage.pyrépertoire et que vous souhaitez exécuter le test test_adans la TestCasesous-classe Adans un fichier tests.pysous l'application / module, examplevous feriez:

python manage.py test example.tests.A.test_a

Si vous ne voulez pas inclure de dépendance et que vous êtes dans Django 1.6 ou version ultérieure, c'est comme ça que vous faites.

Consultez la documentation Django pour plus d'informations


C'est bien de voir cette fonctionnalité intégrée à Django maintenant.
hekevintran

Je ne peux pas du tout faire fonctionner cela: error: option --pattern not recognizedetinvalid command name
geoidesic

Cela fonctionne très bien dans Django v3!
Kirk le

11

J'avais moi-même ce problème et j'ai trouvé cette question, au cas où quelqu'un d'autre viendrait, voici ce que j'ai déterré. Le DjangoTestSuiteRuner utilise une méthode appelée build_test (label) qui détermine les cas de test à exécuter en fonction de l'étiquette. En examinant cette méthode, il s'avère qu'ils font un getattr () sur le module "models" ou "test". Cela signifie que si vous retournez une suite, le testeur ne recherche pas vos cas de test dans cette suite, il ne recherche que dans l'un de ces modules.

Une solution rapide consiste à utiliser __init__.py importer vos tests directement au lieu de définir une suite. Le les fait partie du module "test" et ainsi build_test (label) peut les trouver.

Pour votre exemple ci-dessus, tests/__init__.pydevrait simplement contenir:

from field_tests import *
from storage_tests import *

Ce n'est pas très élégant et bien sûr si vous essayez de faire quelque chose de plus compliqué avec votre suite, cela ne fonctionnera pas, mais ce serait le cas dans ce cas.




3

Mettez ce code dans votre __init__.py et il importera toutes les classes de test dans le package et les sous-packages. Cela vous permettra d'exécuter des tests spécifiques sans importer manuellement chaque fichier.

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

De même, pour votre suite de tests, vous pouvez simplement utiliser:

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

Maintenant, tout ce que vous avez à faire pour les nouveaux tests est de les écrire et de vous assurer qu'ils sont dans le dossier tests. Fini l'entretien fastidieux des importations!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.