Comment créer une table pendant les tests Django avec managed = False

J'ai un modèle avec managed = False.

class SampleModel(models.Model):
    apple = models.CharField(max_length=30)
    orange = models.CharField(max_length=30)

    class Meta:
        managed = False

J'ai un test unitaire qui crée un SampleModel, mais quand j'exécute le test, je reçois:

DatabaseError: no such table: SAMPLE_SAMPLE_MODEL

Les documents django - https://docs.djangoproject.com/en/dev/ref/models/options/#managed documente ce qui suit:

Pour les tests impliquant des modèles avec managed = False, c'est à vous de assurer les bonnes tables sont créées dans le cadre de l'installation d'essai.

Comment puis-je réellement "créer" les tables pendant la configuration de test? Ou alternativement, Comment puis-je faire en sorte que lorsque j'exécute des tests, Ce modèle a "managed = True" pour la durée du test?

Dans l'application réelle, Ce modèle est en fait soutenu par une vue dans la base de données. Cependant, pour les cours de l'essai, je voudrais traiter cela comme une table et être en mesure d'insérer des données de test là.

28
demandé sur Derek Kwok 2011-08-11 08:50:44

7 réponses

Consultez cet article de blog: http://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/ il décrit en détail la création d'un coureur de test pour les modèles non gérés.

13
répondu Mark Lavin 2011-08-12 02:22:09

Exécutez SQL brut pour créer la table dans la configuration de test:

from django.db import connection

class MyTest(unittest.TestCase):
    def setUp(self):
        connection.cursor().execute("CREATE TABLE ...")

    def tearDown(self):
        connection.cursor().execute("DROP TABLE ...")
4
répondu codeape 2011-08-11 05:17:49

Créez votre propre coureur de test en utilisant 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 """
    #set manage=True for that specific database on here

Ensuite, sur vos paramètres, Ajoutez cette classe à TEST_RUNNER.

3
répondu mohi666 2011-08-11 23:48:09

Une solution rapide si vous n'avez pas beaucoup de tables non gérées:

Ajoutez D'abord une nouvelle variable aux paramètres.

# settings.py
import sys
UNDER_TEST = (len(sys.argv) > 1 and sys.argv[1] == 'test')

, Puis dans les modèles

# models.py
from django.conf import settings

class SampleModel(models.Model):
    apple = models.CharField(max_length=30)
    orange = models.CharField(max_length=30)

    class Meta:
        managed = getattr(settings, 'UNDER_TEST', False)
2
répondu dnozay 2015-07-06 21:30:34

Belle solution plug and play. Il suffit de coller ceci avant la définition de votre classe de test. (note: django 1.8 utilisé)

from django.db.models.loading import get_models

def change_managed_settings_just_for_tests():
  """django model managed bit needs to be switched for tests."""    

  unmanaged_models = [m for m in get_models() if not m._meta.managed]
  for m in unmanaged_models:
    m._meta.managed = True

change_managed_settings_just_for_tests()
2
répondu WojtylaCz 2016-07-18 22:10:59

Juste pour ajouter :django.DB.modèle.chargement.get_models sera supprimé dans Django 1.9 (voir https://github.com/BertrandBordage/django-cachalot/issues/33).

Voici une mise à jour pour Django 1.10:

class UnManagedModelTestRunner(DiscoverRunner):
    '''
    Test runner that automatically makes all unmanaged models in your Django
    project managed for the duration of the test run.
    Many thanks to the Caktus Group 
    '''

    def setup_test_environment(self, *args, **kwargs):
        from django.apps  import apps
        self.unmanaged_models = [m for m in apps.get_models() if not m._meta.managed]
        for m in self.unmanaged_models:
            m._meta.managed = True
        super(UnManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)

    def teardown_test_environment(self, *args, **kwargs):
        super(UnManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
        # reset unmanaged models
        for m in self.unmanaged_models:
            m._meta.managed = False 

REMARQUE Vous devez également prendre soin des migrations(voir Test de l'application django avec plusieurs bases de données héritées )

MIGRATION_MODULES = {
    'news': 'news.test_migrations',
    'economist': 'economist.test_migrations'
}
1
répondu Akavir 2017-05-23 11:47:01

Vous pouvez utiliser SchemaEditor dans TestCase.setUp méthode pour créer explicitement des modèles avec managed = False.

# models.py

from django.db import models


class Unmanaged(models.Model):
    foo = models.TextField()

    class Meta:
        # This model is not managed by Django
        managed = False
        db_table = 'unmanaged_table'

Et dans vos tests:

# tests.py

from django.db import connection
from django.test import TestCase

from myapp.models import Unmanaged


class ModelsTestCase(TestCase):
    def setUp(self):
        super().setUp()

        with connection.schema_editor() as schema_editor:
            schema_editor.create_model(Unmanaged)

            if Unmanaged._meta.db_table not in connection.introspection.table_names():
                raise ValueError("Table `{table_name}` is missing in test database.".format(table_name=Unmanaged._meta.db_table))

    def tearDown(self):
        super().tearDown()

        with connection.schema_editor() as schema_editor:
            schema_editor.delete_model(Unmanaged)

    def test_unmanaged_model(self):
        with self.assertNumQueries(num=3):
            self.assertEqual(0, Unmanaged.objects.all().count())
            Unmanaged.objects.create()
            self.assertEqual(1, Unmanaged.objects.all().count())
0
répondu illagrenan 2018-04-12 15:27:38