Comment lancer des tests pour l’application réutilisable django?

Puis-je lancer des tests pour mon application Django réutilisable sans incorporer cette application dans un projet?

Mon application utilise certains modèles, il est donc nécessaire de fournir les (TEST_)DATABASE_* . Où dois-je les stocker et comment dois-je lancer des tests?

Pour un projet Django, je peux exécuter des tests avec le manage.py test ; Quand django-admin.py test avec mon application autonome, je reçois:

Erreur: les parameters ne peuvent pas être importés, car la variable d’environnement DJANGO_SETTINGS_MODULE n’est pas définie.

Quelles sont les meilleures pratiques ici?

L’utilisation correcte de Django (> = 1.4) est la suivante:

 import django, sys from django.conf import settings settings.configure(DEBUG=True, DATABASES={ 'default': { 'ENGINE': 'django.db.backends.sqlite3', } }, ROOT_URLCONF='myapp.urls', INSTALLED_APPS=('django.consortingb.auth', 'django.consortingb.contenttypes', 'django.consortingb.sessions', 'django.consortingb.admin', 'myapp',)) try: # Django <= 1.8 from django.test.simple import DjangoTestSuiteRunner test_runner = DjangoTestSuiteRunner(verbosity=1) except ImportError: # Django >= 1.8 django.setup() from django.test.runner import DiscoverRunner test_runner = DiscoverRunner(verbosity=1) failures = test_runner.run_tests(['myapp']) if failures: sys.exit(failures) 

DjangoTestSuiteRunner et DiscoverRunner ont principalement des interfaces compatibles.

Pour plus d’informations, vous devriez consulter le document “Définition d’un testeur”:

  • DjangoTestSuiteRunner (Django> = 1.4, <1.8)
  • DiscoverRunner (Django> = 1.8)

J’ai fini avec une telle solution (elle a été inspirée par une solution trouvée dans django-Vote):

Créer un fichier par exemple. ‘runtests.py’ dans les tests dir contenant:

 import os, sys from django.conf import settings DIRNAME = os.path.dirname(__file__) settings.configure(DEBUG = True, DATABASE_ENGINE = 'sqlite3', DATABASE_NAME = os.path.join(DIRNAME, 'database.db'), INSTALLED_APPS = ('django.consortingb.auth', 'django.consortingb.contenttypes', 'django.consortingb.sessions', 'django.consortingb.admin', 'myapp', 'myapp.tests',)) from django.test.simple import run_tests failures = run_tests(['myapp',], verbosity=1) if failures: sys.exit(failures) 

Il permet d’exécuter des tests par la commande python runtests.py . Il ne nécessite pas de dépendances installées (par exemple, buildout) et n’endommage pas les tests exécutés lorsque l’application est incorporée dans un projet plus important.

Pour Django 1.7, c’est légèrement différent. En supposant que vous ayez la structure de répertoires suivante pour app foo :

 foo |── docs |── foo │ ├── __init__.py │ ├── models.py │ ├── urls.py │ └── views.py └── tests ├── foo_models │ ├── __init__.py │ ├── ... │ └── tests.py ├── foo_views │ ├── __init__.py │ ├── ... │ └── tests.py ├── runtests.py └── urls.py 

C’est ainsi que le projet Django lui-même structure ses tests.

Vous voulez lancer tous les tests dans foo/tests/ avec la commande:

 python3 runtests.py 

Vous voulez également pouvoir exécuter la commande à partir d’un répertoire parent de tests , par exemple par Tox ou Invoke, tout comme python3 foo/tests/runtests.py .

La solution que je présente ici est tout à fait réutilisable, seul le nom de l’application, foo doit être ajusté (et des applications supplémentaires, si nécessaire). Ils ne peuvent pas être installés via modify_settings , car ils manqueraient la configuration de la firebase database.

Les fichiers suivants sont nécessaires:

urls.py

 """ This urlconf exists because Django expects ROOT_URLCONF to exist. URLs should be added within the test folders, and use TestCase.urls to set them. This helps the tests remain isolated. """ urlpatterns = [] 

runtests.py

 #!/usr/bin/env python3 import glob import os import sys import django from django.conf import settings from django.core.management import execute_from_command_line BASE_DIR = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.abspath(os.path.join(BASE_DIR, '..'))) # Unfortunately, apps can not be installed via ``modify_settings`` # decorator, because it would miss the database setup. CUSTOM_INSTALLED_APPS = ( 'foo', 'django.consortingb.admin', ) ALWAYS_INSTALLED_APPS = ( 'django.consortingb.auth', 'django.consortingb.contenttypes', 'django.consortingb.sessions', 'django.consortingb.messages', 'django.consortingb.staticfiles', ) ALWAYS_MIDDLEWARE_CLASSES = ( 'django.consortingb.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.consortingb.auth.middleware.AuthenticationMiddleware', 'django.consortingb.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) settings.configure( SECRET_KEY="django_tests_secret_key", DEBUG=False, TEMPLATE_DEBUG=False, ALLOWED_HOSTS=[], INSTALLED_APPS=ALWAYS_INSTALLED_APPS + CUSTOM_INSTALLED_APPS, MIDDLEWARE_CLASSES=ALWAYS_MIDDLEWARE_CLASSES, ROOT_URLCONF='tests.urls', DATABASES={ 'default': { 'ENGINE': 'django.db.backends.sqlite3', } }, LANGUAGE_CODE='en-us', TIME_ZONE='UTC', USE_I18N=True, USE_L10N=True, USE_TZ=True, STATIC_URL='/static/', # Use a fast hasher to speed up tests. PASSWORD_HASHERS=( 'django.consortingb.auth.hashers.MD5PasswordHasher', ), FIXTURE_DIRS=glob.glob(BASE_DIR + '/' + '*/fixtures/') ) django.setup() args = [sys.argv[0], 'test'] # Current module (``tests``) and its submodules. test_cases = '.' # Allow accessing test options from the command line. offset = 1 try: sys.argv[1] except IndexError: pass else: option = sys.argv[1].startswith('-') if not option: test_cases = sys.argv[1] offset = 2 args.append(test_cases) # ``verbosity`` can be overwritten from command line. args.append('--verbosity=2') args.extend(sys.argv[offset:]) execute_from_command_line(args) 

Certains parameters sont facultatifs. ils améliorent la vitesse ou un environnement plus réaliste.

Le deuxième argument pointe vers le répertoire en cours. Il utilise la fonctionnalité de fournir un chemin vers un répertoire pour découvrir des tests sous ce répertoire .

Pour mon application réutilisable ( django-moderation ), j’utilise buildout. Je crée example_project , je l’utilise avec buildout pour exécuter des tests dessus. Je mets simplement mon application dans les parameters de example_project .

Lorsque je veux installer toutes les dépendances utilisées par mon projet et exécuter des tests, il suffit de suivre les étapes suivantes:

  • Exécuter: python bootstrap.py
  • Exécuter le buildout:

    bin / buildout

  • Exécuter des tests pour Django 1.1 et Django 1.2:

    bin / test-1.1 bin / test-1.2

Vous trouverez ici un tutoriel sur la configuration d’une application réutilisable pour utiliser le buildout pour le déploiement et les tests: http://jacobian.org/writing/django-apps-with-buildout/

Vous trouverez ici un exemple de configuration de buildout que j’utilise dans mon projet:

http://github.com/dominno/django-moderation/blob/master//buildout.cfg

Dans un contexte purement pytest , pour fournir juste assez d’environnement Django pour exécuter des tests pour mon application réutilisable sans projet Django réel, j’avais besoin des éléments suivants:

pytest.ini:

 [pytest] DJANGO_SETTINGS_MODULE = test_settings python_files = tests.py test_*.py *_tests.py 

test_settings.py:

 # You may need more or less than what's shown here - this is a skeleton: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', } } INSTALLED_APPS = ( 'django.consortingb.admin', 'django.consortingb.auth', 'django.consortingb.contenttypes', 'django.consortingb.messages', 'django.consortingb.sessions', 'django.consortingb.sites', 'django.consortingb.staticfiles', 'todo', ) ROOT_URLCONF = 'base_urls' TEMPLATES = [ { 'DIRS': ['path/to/your/templates'), ], } ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.consortingb.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.consortingb.auth.middleware.AuthenticationMiddleware', 'django.consortingb.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] 

base_urls.py:

 """ This urlconf exists so we can run tests without an actual Django project (Django expects ROOT_URLCONF to exist.) It is not used by installed instances of this app. """ from django.urls import include, path urlpatterns = [ path('foo/', include('myapp.urls')), ] 

templates / base.html:

Si l’un de vos tests touche des vues réelles, les modèles de votre application étendent probablement le projet base.html , de sorte que le fichier doit exister. Dans mon cas, je viens de créer un fichier vide templates/base.html .

Je peux maintenant exécuter pytest -x -v partir de mon répertoire d’application réutilisable autonome, sans projet Django.