【问题标题】:IntegrityError: duplicate key value in django unit testIntegrityError:django单元测试中的重复键值
【发布时间】:2012-08-08 13:45:55
【问题描述】:

我正在尝试为我的 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.

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

【问题讨论】:

    标签: django unit-testing postgresql


    【解决方案1】:

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

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

    【讨论】:

    • 我意识到 user_id 具有唯一值约束。但事实是我正在运行一个单元测试,因此在测试执行时会创建一个新的测试数据库。结果表都是空的。
    • @user512783:很有可能你被误会了。看表。如果您无法判断代码的哪一行引发了错误,请修剪您的 DBTest 类,直到将其隔离。
    • @Catcall from the docs,“为测试创建单独的空白数据库......当所有测试都执行完毕后,测试数据库被销毁”。如果您说预先存在的数据(在测试运行之前)是问题所在,那么不,不是。如果您说 OP 可以在之后终止测试以检查测试数据库,那当然可以,但是除了 IntegrityError 之外还会提供什么信息?
    • @supervacuo:不,我是说问题出在 OP 的代码中,我建议了一种隔离错误代码的方法。 (修剪代码,观察表格。)说真的,这里的程序员错误胜过 PostgreSQL 错误或 Django 错误,尤其是 that 错误消息。
    • 如果代码从未明确指定主键值并且主键定期初始化(隐式使用 auto_increment) - 那么我希望它递增。非常奇怪的行为不是已经存在不应该有的数据(这本身很奇怪但很好)-而且主键显然没有(正确地)递增。
    【解决方案2】:

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

    【讨论】:

    • 这无法解释为什么主键设置为 auto_increment 时不递增。
    【解决方案3】:

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

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

    因此,正如 zifot 所建议的,您的项目中可能还有一些其他代码创建了 UserProfile。如果操作正确,只需从setUp 中删除您的self.userProfile = models.UserProfile.objects.create(... 行并通过

    访问配置文件
    self.user.get_profile()
    

    【讨论】:

      【解决方案4】:

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

      我有一个模型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()
      

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

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

      这可能表明我应该将这个逻辑移到别处。 (我会这样做。)但是遇到这个很有趣。

      【讨论】:

        猜你喜欢
        • 2011-07-06
        • 2012-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-01
        • 2020-12-18
        相关资源
        最近更新 更多