在Django单元测试中使用User模型的问题
我有一个django的测试案例,运行时出现了错误:
class MyTesting(unittest.TestCase):
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.up1 = UserProfile.objects.create(user=self.u1)
def testA(self):
...
def testB(self):
...
当我运行测试时,testA
会成功通过,但在testB
开始之前,我遇到了以下错误:
IntegrityError: column username is not unique
很明显,它在每个测试之前都试图创建self.u1
,但发现数据库里已经有了这个记录。那么,我该如何让它在每个测试结束后正确清理,以便后面的测试能够正常运行呢?
3 个回答
简单来说,setUp
这个方法的存在就是为了在每个测试用例之前运行一次。
相对的,另一个方法是在每个测试用例之后运行一次,这个方法叫做tearDown
:在这里你可以删除self.u1
等对象(通常只需要调用self.u1.delete()
,除非你还有其他特别的清理需求,不仅仅是删除这个对象)。
如果你想让Django在每次测试结束后自动清空测试数据库,那么你应该扩展 django.test.TestCase
,而不是现在你正在用的 django.utils.unittest.TestCase
。
在每次测试后清空数据库是个好习惯,这样可以确保你的测试结果是一致的。不过要注意,这样会让你的测试变得更慢,因为多了一些额外的处理。
可以查看 警告 部分,在 “编写测试” Django 文档 中。
setUp
和 tearDown
方法是在每个测试用例之前和之后被调用的。在这里,你需要定义一个 tearDown
方法,用来删除创建的用户。
class MyTesting(unittest.TestCase):
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.up1 = UserProfile.objects.create(user=self.u1)
def testA(self):
...
def tearDown(self):
self.up1.delete()
self.u1.delete()
我还建议使用 创建用户资料,可以通过 post_save
信号来实现,除非你真的想为每个用户手动创建用户资料。
关于删除评论的后续说明:
根据 Django 文档:
当 Django 删除一个对象时,它会模拟 SQL 中的 ON DELETE CASCADE 约束的行为——换句话说,任何指向要删除对象的外键的对象也会被一起删除。
在你的情况下,用户资料是指向用户的,所以你应该先删除用户,这样才能同时删除用户资料。