Comment répartir les tests unitaires django sur plusieurs fichiers?

126
  • J'ai une application python-django
  • J'utilise le framework de test unitaire
  • Les tests sont organisés dans le fichier "tests.py" dans le répertoire du module
  • J'exécute les tests via ./manage.py test app

Maintenant..

  • Le tests.pyfichier devient plutôt volumineux / complexe / désordonné
  • J'aimerais diviser tests.pyen plus petites collections de tests ...

Comment?

John Mee
la source

Réponses:

47

Le comportement a changé dans Django 1.6, il n'est donc plus nécessaire de créer un package. Nommez simplement vos fichiers test*.py.

Depuis la documentation Django 1.7

Lorsque vous exécutez vos tests, le comportement par défaut de l'utilitaire de test est de trouver tous les cas de test (c'est-à-dire les sous-classes de unittest.TestCase) dans tout fichier dont le nom commence par test, de créer automatiquement une suite de tests à partir de ces cas de test, et exécutez cette suite.

À partir de la documentation Django 1.6 ,

La découverte de test est basée sur la découverte de test intégrée du module unittest. Par défaut, cela découvrira les tests dans n'importe quel fichier nommé «test * .py» sous le répertoire de travail actuel.

Comportement précédent, issu de la documentation Django 1.5 :

Lorsque vous exécutez vos tests, le comportement par défaut de l'utilitaire de test est de trouver tous les cas de test (c'est-à-dire les sous-classes de unittest.TestCase) dans models.py et tests.py, de créer automatiquement une suite de tests à partir de ces cas de test, et exécutez cette suite.

Il existe une deuxième façon de définir la suite de tests pour un module: si vous définissez une fonction appelée suite () dans models.py ou tests.py, le lanceur de tests Django utilisera cette fonction pour construire la suite de tests pour ce module. Cela suit l'organisation suggérée pour les tests unitaires. Consultez la documentation Python pour plus de détails sur la construction d'une suite de tests complexe.

osa
la source
4
Dans django 2.6 on ne découvre vraiment rien…
LtWorf
2
Actuellement en utilisant Django 1.10, je voulais mettre tous mes test*.pyfichiers dans un dossier appelé testspour garder le dossier propre - c'est possible, mais vous devez exécuter ./manage.py test app.testset toutes les importations relatives doivent monter d'un niveau ( from .modelsdevient from ..models).
Scott Stevens
123

Notez que cette approche n'est plus valable depuis Django 1.6, voir ce post .

Vous pouvez créer un testsdossier avec ___init___.pyinside (pour qu'il devienne un package). Ensuite, vous y ajoutez vos fichiers .py de test fractionné et les importez tous dans ___init___.py.

Ie: Remplacez le test.py fichier par un module qui ressemble et agit comme le fichier:

Créer un testsrépertoire sous l'application en question

app
app \ models.py
app \ views.py
application \ tests
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Importez les sous-modules dans app\tests\__init__.py:

from bananas import *
from apples import *

Vous pouvez désormais utiliser ./manage.py comme s'ils étaient tous dans un seul fichier:

./manage.py test app.some_test_in_bananas
Tomasz Zieliński
la source
1
Doh. Vous vouliez créer un module «tests» sous l'application que je teste; pas une nouvelle application appelée tests. Je comprends maintenant. Impressionnant. Merci!
John Mee
@John: Je ne peux plus reconnaître ma réponse! :-) Mais vous avez tout à fait raison de dire que c'était trop vague, même si c'est correct - vos exemples le montrent clairement, contrairement à ma formulation originale.
Tomasz Zieliński
2
@Tomasz .. Vos paroles sont toujours là - totalement intactes. Je viens de l'étoffer un peu depuis que vous m'avez mis sur la bonne voie.
John Mee
@John: Je n'étais pas du tout en colère si c'est ce que tu veux dire :) C'était juste drôle de voir ma propre réponse sous une forme un peu différente
Tomasz Zieliński
4
@jMyles, si vous voulez dire par "testeur de django régulier", python manage.py test myappalors en fait cette réponse fonctionne très bien. (juste essayé)
Kirk Woll
27

La réponse donnée par Tomasz est correcte. Cependant, il peut devenir fastidieux de s'assurer que les importations en__init__.py correspondent à votre structure de fichiers.

Pour détecter automatiquement tous les tests dans le dossier, vous pouvez ajouter ceci dans __init__.py:

import unittest

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

Cela vous permettra d'exécuter ./manage.py test appnamemais ne gérera pas l'exécution de tests spécifiques. Pour ce faire, vous pouvez utiliser ce code (également dans __init__.py):

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__)

Vous pouvez maintenant exécuter tous vos tests via manage.py test appou des tests spécifiques viamanage.py test app.TestApples

Bryce Drennan
la source
Où placez-vous la deuxième pièce?
rh0dium
Les deux morceaux entrent dans__init__.py
Bryce Drennan
Notez que si l'un de vos noms de package de test coïncide avec les noms de module de niveau supérieur qui sont importés pendant l'exécution du test, l'extrait de code pkgutil entraînera l'échec de l'importation car les tests sont ajoutés en tant que sys.modules[packagename]. Une solution de contournement rapide consiste à deltout ce qui pose des problèmes après ce qui précède. (Ou vous pouvez renommer vos dossiers;))
Paul Fenney
C'est génial mais j'ai rencontré une erreur où, lors de l'exécution d'un test au niveau de l'application ( python manage.py test appName), le deuxième bit de code lèverait une erreur indiquant qu'il __path__n'était pas disponible. Je l'ai évité en enveloppant le deuxième extrait de code dans un if '__path__' in locals():chèque, ce qui a fait l'affaire. Merci d'avoir répondu!
alukach
1
+1 cela garantit également que le fichier init respecte les normes de codage communes, c'est-à-dire qu'il n'a pas de * ou d'importations inutilisées
Martin B.
13

Créez simplement votre structure de répertoires comme ceci:

myapp/
    __init__.py
    tests/
        __init__.py
        test_one.py
        test_two.py
        ...
    ...

Et python manage.py test myappfonctionnera comme prévu.

Spiderlama
la source
5

http://docs.python.org/library/unittest.html#organizing-tests parle de la division des fichiers en modules, et la section juste au-dessus contient un exemple.

Jim Deville
la source
2
Le «petit plus» que je recherche, par rapport à rtfm, est l'environnement des paramètres de django, la base de données et les appareils pour les tests.
John Mee
2

Pas besoin de coder quoi que ce soit dans init. Créez simplement un sous-répertoire dans votre application. La seule exigence est de ne pas l'appeler tests * Par exemple

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py
MaxBlax360
la source
1
Pourquoi ne pouvez-vous pas l'appeler quelque chose qui commence par des "tests"?
Serp C
J'utilise cette réponse avec Django 1.11.4. Raisons de l'utiliser: (1) Le fichier "app / testing / __ init__.py" reste vide et (2) La commande reste la base "python manage.py test app"
rprasad
2

Avec Django 2.2, une solution simple et assez bonne pourrait être de créer un testdossier dans une application, et vous pouvez y placer vos test_...pyfichiers associés , il suffit de les ajouter __init__.pyau testdossier.

Gabor
la source
1

Si vous avez une configuration plus compliquée ou si vous ne souhaitez pas utiliser d' from ... import *instructions -type, vous pouvez définir une fonction appelée suitedans votre tests.py (ou tests / __ init__.py), qui renvoie une instance de unittest.TestSuite.

Joel Cross
la source
0

Je pense qu'il ./manage.py testsuffit d'exécuter toutes les astuces de tests (dans django> = 1.7).

Si vos tests d'organisation concernent le regroupement et le cherrypicking et que vous êtes fan de l' noseutilisation du nez de django :

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

Si vous connaissez le nez, alors vous savez comment "joker" beaucoup plus agréable sur tous vos fichiers.

PS

C'est juste une meilleure pratique. J'espère que cela pourra aider. La réponse a été empruntée ici: exécuter un cas de test spécifique dans Django lorsque votre application a un répertoire de tests

Yauhen Yakimovich
la source
0

J'ai deux fichiers. L'un est tests.pyet l'autre est test_api.py. Je peux les exécuter individuellement comme ci-dessous.

   manage.py test companies.tests
   manage.py test companies.test_api

Reportez-vous à la réponse de @ osa concernant la convention de dénomination des fichiers.

kta
la source