Django: la meilleure façon de tester un modèle abstrait
j'ai besoin d'écrire quelques tests unitaires pour un modèle de base abstrait, qui fournit certaines fonctionnalités de base qui devraient être utilisées par d'autres applications. Il serait nécessaire de définir un modèle qui en hérite uniquement à des fins d'essai; existe-t-il des moyens élégants/simples de définir ce modèle juste pour le test?
j'ai vu des "hacks" qui rendent cela possible, mais jamais vu un "officiel" dans la documentation de django ou dans d'autres lieux similaires.
8 réponses
je viens de tomber sur cette fonctionnalité moi-même: vous pouvez juste hériter de votre modèle abstrait en tests.py et testez ça comme d'habitude. Quand tu cours manage.py tests', Django crée non seulement une base de données de tests, mais valide aussi et synchronise vos modèles de tests.
Testé avec le tronc Django actuel (version 1.2).
je suis tombé sur ce récemment et je voulais le mettre à jour pour les nouvelles versions de Django (1.9 et plus tard) vous pouvez utiliser le schéma create_model
au lieu de l'obsolète sql_create_model
from django.db import connection
from django.db.models.base import ModelBase
from django.test import TestCase
class ModelMixinTestCase(TestCase):
"""
Base class for tests of model mixins. To use, subclass and specify
the mixin class variable. A model using the mixin will be made
available in self.model.
"""
def setUp(self):
# Create a dummy model which extends the mixin
self.model = ModelBase('__TestModel__' + self.mixin.__name__, (self.mixin,), {'__module__': self.mixin.__module__})
# Create the schema for our test model
with connection.schema_editor() as schema_editor:
schema_editor.create_model(self.model)
def tearDown(self):
# Delete the schema for the test model
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(self.model)
j'ai la même situation. J'ai fini par utiliser une version de la solution @dylanboxalot. J'ai eu des détails supplémentaires de ici spécifiquement après avoir lu la section "Aperçu de la structure D'essai".
setUp
et tearDown
méthodes sont appelées à chaque fois qu'un test est à exécuter. Une meilleure solution consiste à lancer la création du modèle "abstrait" Une fois, avant que tous les tests ne soient lancés. Pour ce faire, vous pouvez mettre en œuvre l' setUpClassData
et aussi mettre en œuvre les tearDownClass
.
class ModelMixinTestCase(TestCase):
'''
Base class for tests of model mixins. To use, subclass and specify the
mixin class variable. A model using the mixin will be made available in
self.model
'''
@classmethod
def setUpClass(cls):
# Create a dummy model which extends the mixin
cls.model = ModelBase('__TestModel__' +
cls.mixin.__name__, (cls.mixin,),
{'__module__': cls.mixin.__module__}
)
# Create the schema for our test model
with connection.schema_editor() as schema_editor:
schema_editor.create_model(cls.model)
super(ModelMixinTestCase, cls).setUpClass()
@classmethod
def tearDownClass(cls):
# Delete the schema for the test model
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(cls.model)
super(ModelMixinTestCase, cls).tearDownClass()
Une possible mise en œuvre peut ressembler à ceci:
class MyModelTestCase(ModelMixinTestCase):
mixin = MyModel
def setUp(self):
# Runs every time a test is run.
self.model.objects.create(pk=1)
def test_my_unit(self):
# a test
aModel = self.objects.get(pk=1)
...
Peut-être ModelMixinTestCase
la classe devrait être ajoutée à Django? :P
je pense que ce que vous cherchez est quelque chose comme ceci.
voici le code complet du lien:
from django.test import TestCase
from django.db import connection
from django.core.management.color import no_style
from django.db.models.base import ModelBase
class ModelMixinTestCase(TestCase):
"""
Base class for tests of model mixins. To use, subclass and specify
the mixin class variable. A model using the mixin will be made
available in self.model.
"""
def setUp(self):
# Create a dummy model which extends the mixin
self.model = ModelBase('__TestModel__'+self.mixin.__name__, (self.mixin,),
{'__module__': self.mixin.__module__})
# Create the schema for our test model
self._style = no_style()
sql, _ = connection.creation.sql_create_model(self.model, self._style)
self._cursor = connection.cursor()
for statement in sql:
self._cursor.execute(statement)
def tearDown(self):
# Delete the schema for the test model
sql = connection.creation.sql_destroy_model(self.model, (), self._style)
for statement in sql:
self._cursor.execute(statement)
mise à Jour pour Django >=2.0
j'ai ajouté quelques vérifications pour aider à résoudre ces problèmes et maintenant il fonctionne parfaitement. J'espère que cela aide les gens
from django.db import connection
from django.db.models.base import ModelBase
from django.db.utils import ProgrammingError
from django.test import TestCase
class AbstractModelMixinTestCase(TestCase):
'''Base class for tests of model mixins/abstract models.
To use, subclass and specify the mixin class variable. A model using
the mixin will be made available in self.model'''
@classmethod
def setUpClass(cls):
# Create a dummy model which extends the mixin. A RuntimeWarning will
# occur if the model is registered twice
if not hasattr(cls, 'model'):
cls.model = ModelBase(
'__TestModel__' +
cls.mixin.__name__, (cls.mixin,),
{'__module__': cls.mixin.__module__}
)
# Create the schema for our test model. If the table already exists,
# will pass
try:
with connection.schema_editor() as schema_editor:
schema_editor.create_model(cls.model)
except OperationalError:
pass
super(AbstractModelMixinTestCase, cls).setUpClass()
@classmethod
def tearDownClass(cls):
# Delete the schema for the test model. If no table, will pass
try:
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(cls.model)
except OperationalError:
pass
super(AbstractModelMixinTestCase, cls).tearDownClass()
à utiliser, mettre en œuvre de la même manière que ci-dessus:
class MyModelTestCase(AbstractModelMixinTestCase):
"""Test abstract model."""
mixin = MyModel
def setUp(self):
self.model.objects.create(pk=1)
def test_a_thing(self):
mod = self.model.objects.get(pk=1)
développez une application d'exemple minimale que vous distribuez avec vos modèles 'abstraits'. Fournir des tests pour l'application exemple pour prouver les modèles abstraits.
j'ai ce problème moi-même et ma solution est sur ce gist django-test-abstrait-modèles
vous pouvez l'utiliser comme ceci:
1 - la sous-classe votre django modèles abstraits
2 - Ecrivez votre cas test comme ceci:
class MyTestCase(AbstractModelTestCase):
self.models = [MyAbstractModelSubClass, .....]
# your tests goes here ...
3-Si vous n'avez pas fourni self.models
attribut il va rechercher l'application courante pour les modèles dans le chemin myapp.tests.models.*
tester une classe abstraite n'est pas très utile, car une classe dérivée peut outrepasser ses méthodes. Les autres applications sont responsables de tester leurs classes en fonction de votre classe abstraite.