在Django单元测试中使用User模型的问题

22 投票
3 回答
13240 浏览
提问于 2025-04-15 22:44

我有一个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 个回答

3

简单来说,setUp这个方法的存在就是为了在每个测试用例之前运行一次

相对的,另一个方法是在每个测试用例之后运行一次,这个方法叫做tearDown:在这里你可以删除self.u1等对象(通常只需要调用self.u1.delete(),除非你还有其他特别的清理需求,不仅仅是删除这个对象)。

10

如果你想让Django在每次测试结束后自动清空测试数据库,那么你应该扩展 django.test.TestCase,而不是现在你正在用的 django.utils.unittest.TestCase

在每次测试后清空数据库是个好习惯,这样可以确保你的测试结果是一致的。不过要注意,这样会让你的测试变得更慢,因为多了一些额外的处理。

可以查看 警告 部分,在 “编写测试” Django 文档 中。

30

setUptearDown 方法是在每个测试用例之前和之后被调用的。在这里,你需要定义一个 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 约束的行为——换句话说,任何指向要删除对象的外键的对象也会被一起删除。

在你的情况下,用户资料是指向用户的,所以你应该先删除用户,这样才能同时删除用户资料。

撰写回答