Django 单元测试:应该如何测试抽象模型?
Django unit testing: How should one test abstract models?
在我的 Django 项目中,我有一个名为 'core' 的应用程序,其中包含我所有的可重用模型混合/抽象模型 (behaviors.py)、模型 (models.py)、视图 (views.py) 和辅助函数 (utils.py):
core/
__init__.py
behaviors.py
models.py
utils.py
views.py
我现在想为这些文件编写测试。对于模型、实用程序和视图,我只是像以前一样编写单元测试。
我现在不确定应该如何测试 behaviors.py 中包含的抽象模型。例如,我有这个模型混合:
import uuid as uuid_lib
from django.db import models
class UniversallyUniqueIdentifiable(models.Model):
uuid = models.UUIDField(
db_index=True,
default=uuid_lib.uuid4,
editable=False
)
class Meta:
abstract = True
如何测试抽象模型?
在one of the articles我以前学过胖模型,作者只是测试他使用抽象模型的模型。但这对我来说感觉不是很干,因为这意味着我必须在我使用它的每个模型中测试 UUID 的添加。
有更好的方法吗?
试试下面的代码
from django.db import connection
from django.db.models.base import ModelBase
from django.test import TestCase
from .models import UniversallyUniqueIdentifiable
import uuid
class TestUniversallyUniqueIdentifiable(TestCase):
model = UniversallyUniqueIdentifiable
def setUp(self):
# Create a dummy model
self.model = ModelBase(
'__TestModel__' + self.model.__name__, (self.model,),
{'__module__': self.model.__module__}
)
# Create the schema for our test model
with connection.schema_editor() as schema_editor:
schema_editor.create_model(self.model)
def test_mytest_case(self):
self.model.objects.create(uuid=uuid.uuid4())
self.assertEqual(self.model.objects.count(), 1)
def tearDown(self):
# Delete the schema for the test model
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(self.model)
Anjaneyulu Batta 的答案令人惊叹,但可读性不强,如果 Django 团队改变 connection
内部行为方式,则可能难以维护。
我会做什么:
- 测试抽象class'通用属性到任何使用这个抽象class的模型。
- 测试此 是 class 的子class 摘要 class。
- 测试此模型的特定属性。
- 对任何其他模型重复 2 和 3。
示例:一个摘要 class Parallelogram
和一个使用它的模型称为 Square
.
from unittest import TestCase
from tetrahedrons.models import Parallelogram, Square
class ParallelogramAbstractModelTest(TestCase):
def test_has_four_sides(self):
...
def test_parallel_opposite_sides(self):
...
class SquareModelTest(TestCase):
def test_subclasses_mobel_base(self):
self.assertTrue(issubclass(Square, Parallelogram))
def test_equal_sides(self):
...
在我的 Django 项目中,我有一个名为 'core' 的应用程序,其中包含我所有的可重用模型混合/抽象模型 (behaviors.py)、模型 (models.py)、视图 (views.py) 和辅助函数 (utils.py):
core/
__init__.py
behaviors.py
models.py
utils.py
views.py
我现在想为这些文件编写测试。对于模型、实用程序和视图,我只是像以前一样编写单元测试。
我现在不确定应该如何测试 behaviors.py 中包含的抽象模型。例如,我有这个模型混合:
import uuid as uuid_lib
from django.db import models
class UniversallyUniqueIdentifiable(models.Model):
uuid = models.UUIDField(
db_index=True,
default=uuid_lib.uuid4,
editable=False
)
class Meta:
abstract = True
如何测试抽象模型? 在one of the articles我以前学过胖模型,作者只是测试他使用抽象模型的模型。但这对我来说感觉不是很干,因为这意味着我必须在我使用它的每个模型中测试 UUID 的添加。 有更好的方法吗?
试试下面的代码
from django.db import connection
from django.db.models.base import ModelBase
from django.test import TestCase
from .models import UniversallyUniqueIdentifiable
import uuid
class TestUniversallyUniqueIdentifiable(TestCase):
model = UniversallyUniqueIdentifiable
def setUp(self):
# Create a dummy model
self.model = ModelBase(
'__TestModel__' + self.model.__name__, (self.model,),
{'__module__': self.model.__module__}
)
# Create the schema for our test model
with connection.schema_editor() as schema_editor:
schema_editor.create_model(self.model)
def test_mytest_case(self):
self.model.objects.create(uuid=uuid.uuid4())
self.assertEqual(self.model.objects.count(), 1)
def tearDown(self):
# Delete the schema for the test model
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(self.model)
Anjaneyulu Batta 的答案令人惊叹,但可读性不强,如果 Django 团队改变 connection
内部行为方式,则可能难以维护。
我会做什么:
- 测试抽象class'通用属性到任何使用这个抽象class的模型。
- 测试此 是 class 的子class 摘要 class。
- 测试此模型的特定属性。
- 对任何其他模型重复 2 和 3。
示例:一个摘要 class Parallelogram
和一个使用它的模型称为 Square
.
from unittest import TestCase
from tetrahedrons.models import Parallelogram, Square
class ParallelogramAbstractModelTest(TestCase):
def test_has_four_sides(self):
...
def test_parallel_opposite_sides(self):
...
class SquareModelTest(TestCase):
def test_subclasses_mobel_base(self):
self.assertTrue(issubclass(Square, Parallelogram))
def test_equal_sides(self):
...