143 votes

django tests unitaires sans db

Est-il possible d'écrire django unittests sans mettre en place une db? Je veux tester la logique métier qui ne nécessite pas de la db. Et alors qu'il est rapide pour l'installation de la base de données, je n'ai pas vraiment besoin dans certaines situations.

135voto

mohi666 Points 1506

Vous pouvez sous-classe DjangoTestSuiteRunner et remplacer setup_databases et teardown_databases méthodes de passer.

Créer un nouveau fichier de paramètres et de définir TEST_RUNNER à la nouvelle classe que vous venez de créer. Ensuite, lorsque vous exécutez votre test, indiquez votre nouveau fichier de paramètres-paramètres de l'indicateur.

Voici ce que j'ai fait:

Créer un custom test (test personnalisé maillot de coureur de similaire à ceci:

from django.test.simple import DjangoTestSuiteRunner

class NoDbTestRunner(DjangoTestSuiteRunner):
  """ A test runner to test without database creation """

  def setup_databases(self, **kwargs):
    """ Override the database creation defined in parent class """
    pass

  def teardown_databases(self, old_config, **kwargs):
    """ Override the database teardown defined in parent class """
    pass

Créer des paramètres personnalisés:

from mysite.settings import *

# Test runner with no database creation
TEST_RUNNER = 'mysite.scripts.testrunner.NoDbTestRunner'

Lorsque vous exécutez vos tests, de l'exécuter comme suit --paramètres de l'indicateur est défini pour votre nouveau fichier de paramètres:

python manage.py test myapp --settings='no_db_settings'

101voto

Ali Points 166

Généralement, les tests d'une application peuvent être classés en deux catégories

  1. Les tests unitaires, ces test de l'individu extraits de code dans l'insolation et ne nécessitent pas d'aller à la base de données
  2. L'intégration des cas de test qui vont effectivement à la base de données et de tester l'intégration de la logique.

Django prend en charge les deux tests unitaires et d'intégration.

Les tests unitaires, ne nécessite pas d'installation et le démontage de la base de données et nous nous devrait hériter de SimpleTestCase.

from django.test import SimpleTestCase


class ExampleUnitTest(SimpleTestCase):
    def test_something_works(self):
    self.assertTrue(True)

Pour l'intégration des cas de test hériter de cas de test à son tour hérite de TransactionTestCase et il va l'installation et le démontage de la base de données avant l'exécution de chaque test.

from django.test import TestCase


class ExampleIntegrationTest(TestCase):
    def test_something_works(self):
        #do something with database
        self.assertTrue(True)

Cette stratégie permettra d'assurer que la base de données créée et détruite seulement pour les cas de test d'accès à la base de données et, par conséquent, des tests seront plus efficaces

32voto

themadmax Points 46

D' django.test.simple

  warnings.warn(
      "The django.test.simple module and DjangoTestSuiteRunner are deprecated; "
      "use django.test.runner.DiscoverRunner instead.",
      RemovedInDjango18Warning)

Afin de remplacer DiscoverRunner au lieu de DjangoTestSuiteRunner.

 from django.test.runner import DiscoverRunner

 class NoDbTestRunner(DiscoverRunner):
   """ A test runner to test without database creation/deletion """

   def setup_databases(self, **kwargs):
     pass

   def teardown_databases(self, old_config, **kwargs):
     pass

L'utilisation de ce genre :

python manage.py test app --testrunner=app.filename.NoDbTestRunner

9voto

Paul Points 138

J'ai choisi d'hériter d' django.test.runner.DiscoverRunner et de faire quelques ajouts à l' run_tests méthode.

Mon premier ajout vérifie si la configuration de la base de données est nécessaire et permet à la normale setup_databases de la fonctionnalité coup de pied dans si une base de données est nécessaire. Ma deuxième plus permet à la normale teardown_databases à exécuter si l' setup_databases méthode a été autorisé à s'exécuter.

Mon code suppose que tous les cas de test qui hérite de django.test.TransactionTestCase (et donc de django.test.TestCase) nécessite une base de données de configuration. J'ai fait cette hypothèse parce que le Django docs disent:

Si vous avez besoin l'un de l'autre de plus en plus complexes et luxueux de Django fonctionnalités spécifiques comme ... les Essais ou l'utilisation de l'ORM ... alors vous devriez utiliser TransactionTestCase ou de cas de test à la place.

https://docs.djangoproject.com/en/1.6/topics/testing/tools/#django.test.SimpleTestCase

mysite/scripts/settings.py

from django.test import TransactionTestCase     
from django.test.runner import DiscoverRunner


class MyDiscoverRunner(DiscoverRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):
        """
        Run the unit tests for all the test labels in the provided list.

        Test labels should be dotted Python paths to test modules, test
        classes, or test methods.

        A list of 'extra' tests may also be provided; these tests
        will be added to the test suite.

        If any of the tests in the test suite inherit from
        ``django.test.TransactionTestCase``, databases will be setup. 
        Otherwise, databases will not be set up.

        Returns the number of tests that failed.
        """
        self.setup_test_environment()
        suite = self.build_suite(test_labels, extra_tests)
        # ----------------- First Addition --------------
        need_databases = any(isinstance(test_case, TransactionTestCase) 
                             for test_case in suite)
        old_config = None
        if need_databases:
        # --------------- End First Addition ------------
            old_config = self.setup_databases()
        result = self.run_suite(suite)
        # ----------------- Second Addition -------------
        if need_databases:
        # --------------- End Second Addition -----------
            self.teardown_databases(old_config)
        self.teardown_test_environment()
        return self.suite_result(suite, result)

Enfin, j'ai ajouté la ligne suivante à mon projet settings.py fichier.

mysite/settings.py

TEST_RUNNER = 'mysite.scripts.settings.MyDiscoverRunner'

Maintenant, lors de l'exécution de seulement de non-db-dépendante des tests, mon test suite exécute un ordre de grandeur plus rapide! :)

6voto

Rockallite Points 178

@Cesar est droit. Après la chute accidentelle ./manage.py test --settings=no_db_settings, sans spécifier un nom d'application, développement de base de données a été anéantie.

Pour des conditions de sécurité accrue, utilisez le même NoDbTestRunner, mais en liaison avec les suivantes, mysite/no_db_settings.py:

from mysite.settings import *

# Test runner with no database creation
TEST_RUNNER = 'mysite.scripts.testrunner.NoDbTestRunner'

# Use an alternative database as a safeguard against accidents
DATABASES['default']['NAME'] = '_test_mysite_db'

Vous devez créer une base de données appelée _test_mysite_db à l'aide d'un outil de base de données. Ensuite, exécutez la commande suivante pour créer les tables correspondantes:

./manage.py syncdb --settings=mysite.no_db_settings

Si vous utilisez Sud, exécutez la commande suivante:

./manage.py migrate --settings=mysite.no_db_settings

OK!

Vous pouvez maintenant exécuter des tests unitaires hyper rapide (et de sécurité) par:

./manage.py test myapp --settings=mysite.no_db_settings

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X