IntegrityError:django单元测试中的重复键值

时间:2012-08-11 14:28:00

标签: django unit-testing postgresql

我正在尝试为我的django项目运行以下单元测试:

from django.test import TestCase
from django.contrib.auth.models import User
from CarbonEmissions import models

class DbTest(TestCase):
    #is called before each test case (e.g test_insertingUserProfiles)
    def setUp(self):
        self.user = User.objects.create(username='ppoliani')
        self.userProfile = models.UserProfile.objects.create(user=self.user, title='Mr', type='student', occupation='student')

    def test_insertingUserProfiles(self):
        """
            Testing the insertion of user profiles into our datbase 
        """
        self.assertEqual(self.user.get_profile().title,'Mr')

    #is called after each test case (e.g test_insertingUserProfiles)
    def tearDown(self):
        self.user.delete()
        self.userProfile.delete()

测试未能抛出以下错误:

IntegrityError: duplicate key value violates unique constraint "CarbonEmissions_userprofile_user_id_key" DETAIL:  Key (user_id)=(1) already exists.

我无法理解该代码有什么问题。

4 个答案:

答案 0 :(得分:2)

错误消息告诉您约束“CarbonEmissions_userprofile_user_id_key”失败,因为在某些表中,已经有一行user_id等于1。

要解决这个问题,最简单的方法是使用pgAdminIII查看约束和数据,pgAdminIII通常与PostgreSQL一起安装。展开表名以查看列,约束等。展开约束以查看其名称和属性。右键单击表名,然后选择“查看数据”以查看允许您浏览数据的选项。

答案 1 :(得分:0)

也许用户配置文件对象已经被一些监听User对象的post_save信号的代码创建了?如果是这样,那么您在setUp函数中创建的配置文件是重复的。

答案 2 :(得分:0)

您尚未发布完整的堆栈跟踪(请执行!)但我认为错误位于创建UserProfile对象的行上。在AUTH_PROFILE_MODULE中指定配置文件类的Django文档explicitly say在添加新用户时自动创建该类型的模型:

  

方法get_profile()如果不存在,则不会创建配置文件。您需要为User模型的django.db.models.signals.post_save信号注册一个处理程序,并且在处理程序中,如果创建为True,则创建关联的用户配置文件:

因此,正如zifot建议的那样,您的项目中可能还有一些其他代码正在创建UserProfile。如果它正确执行,只需从self.userProfile = models.UserProfile.objects.create(...移除setUp行,然后通过

访问个人资料
self.user.get_profile()

答案 3 :(得分:0)

这是一个老问题,但我最近遇到了类似的问题。

我有一个模型Quote,其中有一个名为reported的字段。我最近将此字段更改为私有,并创建了一个属性来设置并获取它。 (因为它必须更新另一个模型,我不想通过信号或串行器来执行此逻辑。)当我更改它时,我在单元测试中得到了相同的错误。

我的模型(简化)是

class Quote(TimeStampedModel):

    _reported = models.BooleanField(
        default=False,
    )

    @property
    def reported(self):
        return self._reported

    @reported.setter
    def reported(self, value):
        self._reported = value
        if value:
            try:
                self.authorization_form.reported = True
                self.authorization_form.save()
            except AuthorizationForm.DoesNotExist:
                pass
        self.save()

我的单元测试失败是

def test_can_set_reported(self):
    quote = Quote.objects.create(
        reported=True,
    )

为了让它通过,我将其改为

def test_can_set_reported(self):
    quote = Quote.objects.create(
        # reported=True,
    )
    quote.reported = True
    quote.save()

我怀疑,问题是我在设置save()时调用了reported方法。因此,管理器创建了对象并设置了reported字段(称为save),然后尝试保存实例。这可能都发生在单个事务中,因此引入了重复键。

查看堆栈跟踪是值得的,我注意到两个插入语句。

这可能表明我应该把这个逻辑转移到其他地方。 (我会这样做。)但遇到这个很有意思。