我目前正在使用 Django 的单元测试(基于 Python 标准库模块:unittest)编写测试。我已经为我的 Contact 模型编写了这个测试,它通过了:
class ContactTestCase(TestCase):
def setUp(self):
"""Create model objects."""
Contact.objects.create(
name='Jane Doe',
email='[email protected]',
phone='+2348123940567',
subject='Sample Subject',
message='This is my test message for Contact object.'
)
def test_user_can_compose_message(self):
""" Test whether a user can compose a messsage in the contact form."""
test_user = Contact.objects.get(name='Jane Doe')
self.assertEqual(test_user.email, '[email protected]')
self.assertEqual(test_user.phone, '+2348123940567')
self.assertEqual(test_user.subject, 'Sample Subject')
self.assertEqual(test_user.message, 'This is my test message for Contact object.')
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.005s
OK
Destroying test database for alias 'default'...
但是,我必须在这个测试中使用
assertEqual
方法 4 次(当测试具有更多字段的模型时可能会更多)。这似乎不遵循 DRY 原则。
我从
文档
测试中知道第一个和第二个是相等的。如果这些值不相等,测试就会失败。
assertEqual(first, second, msg=None)
是否有解决方法或更优雅的方法来编写此类测试?
Is there a workaround or a more elegant approach to writing such tests?
你说的对,一遍遍重复使用
assertEqual
会让你的测试代码冗长且难以维护,尤其是在有很多字段需要校验的时候。
这里提供几种更优雅地编写 Django 单元测试,并遵循 DRY 原则的方法:
1. 使用字典和循环:
你可以创建一个包含预期值的字典,然后循环遍历它来进行断言:
class ContactTestCase(TestCase):
def setUp(self):
"""Create model objects."""
Contact.objects.create(
name='Jane Doe',
email='[email protected]',
phone='+2348123940567',
subject='Sample Subject',
message='This is my test message for Contact object.'
)
def test_user_can_compose_message(self):
""" Test whether a user can compose a message in the contact form."""
test_user = Contact.objects.get(name='Jane Doe')
expected_values = {
'email': '[email protected]',
'phone': '+2348123940567',
'subject': 'Sample Subject',
'message': 'This is my test message for Contact object.'
}
for field, expected_value in expected_values.items():
self.assertEqual(getattr(test_user, field), expected_value, f"{field} does not match expected value")
2. 使用
assertDictEqual
(针对多个字段):
如果你的模型字段和预期值可以构成一个字典,你可以直接使用
assertDictEqual
:
from django.forms.models import model_to_dict
class ContactTestCase(TestCase):
# ... (setUp 方法同上)
def test_user_can_compose_message(self):
""" Test whether a user can compose a message in the contact form."""
test_user = Contact.objects.get(name='Jane Doe')
expected_data = {
'email': '[email protected]',
'phone': '+2348123940567',
'subject': 'Sample Subject',
'message': 'This is my test message for Contact object.'
}
self.assertDictEqual(model_to_dict(test_user, fields=expected_data.keys()), expected_data)
3. 使用自定义断言方法:
你可以创建一个自定义断言方法来比较模型实例和预期值:
class ContactTestCase(TestCase):
# ... (setUp 方法同上)
def assertContactDataEqual(self, contact, **expected_data):
for field, expected_value in expected_data.items():
self.assertEqual(getattr(contact, field), expected_value, f"{field} does not match expected value")
def test_user_can_compose_message(self):
""" Test whether a user can compose a message in the contact form."""
test_user = Contact.objects.get(name='Jane Doe')
self.assertContactDataEqual(
test_user,
email='[email protected]',
phone='+2348123940567',
subject='Sample Subject',
message='This is my test message for Contact object.'
)
4. 使用 Factory Boy 或 Model Bakery 生成测试数据:
这些第三方库可以帮助你更方便地生成测试数据,并可以减少重复代码。
例如,使用 Factory Boy:
import factory
from .models import Contact
class ContactFactory(factory.django.DjangoModelFactory):
class Meta:
model = Contact
name = factory.Faker('name')
email = factory.Faker('email')
phone = factory.Faker('phone_number')
subject = factory.Faker('sentence')
message = factory.Faker('paragraph')
class ContactTestCase(TestCase):
def test_user_can_compose_message(self):
test_user = ContactFactory()
self.assertEqual(test_user.email, test_user.email) # 验证数据是否生成成功
选择哪种方法取决于你的个人偏好和项目的具体情况。但是,这些方法都可以帮助你编写更简洁、更易维护的 Django 单元测试。
标签:python,django,python-unittest,django-testing,django-unittest From: 78841378