我正在尝试使用 django 2.2.4/sqlite3 2.6.0/python 3.6.8 测试一些简单的抽象混合。
目前,我在使用架构编辑器从测试数据库中删除模型时遇到问题。
我有以下测试用例:
from django.test import TestCase
from django.db.models.base import ModelBase
from django.db import connection
class ModelMixinTestCase(TestCase):
"""
Test Case for abstract mixin models.
"""
mixin = None
model = None
@classmethod
def setUpClass(cls) -> None:
# Create a real model from the mixin
cls.model = ModelBase(
"__Test" + cls.mixin.__name__,
(cls.mixin,),
{'__module__': cls.mixin.__module__}
)
# Use schema_editor to create schema
with connection.schema_editor() as editor:
editor.create_model(cls.model)
super().setUpClass()
@classmethod
def tearDownClass(cls) -> None:
# Use schema_editor to delete schema
with connection.schema_editor() as editor:
editor.delete_model(cls.model)
super().tearDownClass()
可以这样使用:
class MyMixinTestCase(ModelMixinTestCase):
mixin = MyMixin
def test_true(self):
self.assertTrue(True)
这确实允许创建和测试模型。问题是,在
ModelMixinTestCase.tearDownClass
中,connection.schema_editor()
无法禁用在 django.db.backends.sqlite3.base
中使用以下命令完成的约束检查:
def disable_constraint_checking(self):
with self.cursor() as cursor:
cursor.execute('PRAGMA foreign_keys = OFF')
# Foreign key constraints cannot be turned off while in a multi-
# statement transaction. Fetch the current state of the pragma
# to determine if constraints are effectively disabled.
enabled = cursor.execute('PRAGMA foreign_keys').fetchone()[0]
return not bool(enabled)
这会导致
__enter__
中的 DatabaseSchemaEditor
出现异常:django.db.backends.sqlite3.schema
因此,基于所有这些,我假设我们处于原子上下文中,但我目前不确定退出该上下文并删除模型的最干净的方法是什么。
def __enter__(self):
# Some SQLite schema alterations need foreign key constraints to be
# disabled. Enforce it here for the duration of the schema edition.
if not self.connection.disable_constraint_checking():
raise NotSupportedError(
'SQLite schema editor cannot be used while foreign key '
'constraint checks are enabled. Make sure to disable them '
'before entering a transaction.atomic() context because '
'SQLite does not support disabling them in the middle of '
'a multi-statement transaction.'
)
return super().__enter__()
正常关闭事务,然后从测试数据库中删除模型。本质上我们只是首先调用
TestCase
而不是最后一个。模型混合测试用例
super().tearDownClass()
使用示例1
class ModelMixinTestCase(TestCase):
"""
Test Case for abstract mixin models.
Subclass and set cls.mixin to your desired mixin.
access your model using cls.model.
"""
mixin = None
model = None
@classmethod
def setUpClass(cls) -> None:
# Create a real model from the mixin
cls.model = ModelBase(
"__Test" + cls.mixin.__name__,
(cls.mixin,),
{'__module__': cls.mixin.__module__}
)
# Use schema_editor to create schema
with connection.schema_editor() as editor:
editor.create_model(cls.model)
super().setUpClass()
@classmethod
def tearDownClass(cls) -> None:
# allow the transaction to exit
super().tearDownClass()
# Use schema_editor to delete schema
with connection.schema_editor() as editor:
editor.delete_model(cls.model)
# close the connection
connection.close()
使用示例2
class MyMixinTestCase(ModelMixinTestCase):
mixin = MyMixin
def test_true(self):
self.assertTrue(True)
但是当在具有相同模型的不同测试用例上重用 mixin 时,我遇到了警告:
class SortableModelMixinTestCase(ModelMixinTestCase):
mixin = SortableModelMixin
def setUp(self) -> None:
self.objects = [self.model.objects.create(pk=i) for i in range(10)]
def test_order_linear(self) -> None:
i = 1
for item in self.objects:
self.assertEqual(i, item.sortable_order)
i += 1
我通过检查模型是否已在应用程序中注册来解决这个问题:
RuntimeWarning: Model '<model_name>' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models.