测试抽象模型-Django 2.2.4/sqlite3 2.6.0 [英] Testing abstract models - django 2.2.4 / sqlite3 2.6.0
问题描述
我正在尝试使用django 2.2.4/sqlite3 2.6.0/python 3.6.8测试一些简单的抽象mixins.
I'm trying to test some simple abstract mixins using django 2.2.4/sqlite3 2.6.0/python 3.6.8.
目前,我在使用架构编辑器从测试数据库中删除模型时遇到问题.
Currently I'm having issues deleting a model from the test database using the schema editor.
我有以下测试案例:
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中完成的约束检查.
使用:
This does allow for a model to be created and tested. The problem is that within ModelMixinTestCase.tearDownClass
, connection.schema_editor()
is unable to disable constraint checking which is done in django.db.backends.sqlite3.base
using:
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)
这会导致 django.db.backends.sqlite3.schema
中的 DatabaseSchemaEditor
的 __ enter __
中出现异常:
this leads to an exception in __enter__
of the DatabaseSchemaEditor
in 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__()
因此,基于所有这些,我假设我们处于原子上下文中,但是我目前不知道退出该上下文并删除模型的最干净方法是什么.
So based on all this I'm assuming we are in an atomic context but I'm currently not sure what the cleanest way is to exit that context and delete the model.
推荐答案
简单解决方案
因此,在进行一些挖掘和测试之后,最好让Django的 TestCase
正常关闭事务,然后从测试数据库中删除模型.本质上,我们只是先调用 super().tearDownClass()
而不是最后一个.
Simple Solution
So after a little digging and testing it seems that it's best to let django's TestCase
close the transaction normally and then remove the model from the test database. Essentially we just call the super().tearDownClass()
first instead of last.
由于这是一个有用的课程,我将发布完整的课程,供其他人复制/粘贴.
Since it's a useful class I'll post the full class for others to copy/paste.
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()
示例用法1
class MyMixinTestCase(ModelMixinTestCase):
mixin = MyMixin
def test_true(self):
self.assertTrue(True)
示例用法2
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
这篇关于测试抽象模型-Django 2.2.4/sqlite3 2.6.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!