2012-08-11 52 views
4

我试图运行下面的单元测试我的Django项目:IntegrityError:在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. 

我可以不明白该代码有什么问题。

回答

2

该错误消息告诉您约束“CarbonEmissions_userprofile_user_id_key”失败,因为在某些表中,已经是一个已经user_id说明等于1

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

+1

我意识到user_id具有唯一的值约束。但事实是,我正在运行单元测试,因此在测试执行时会创建一个新的测试数据库。结果表格全部是空的。 – ppoliani 2012-08-11 16:15:12

+0

@ user512783:赔率有利于您的误解。看看桌子。如果您无法确定代码的哪一行会引发错误,请修剪您的DBTest类,直至将其隔离。 – 2012-08-11 20:52:52

+0

@Catcall [来自文档](https://docs.djangoproject.com/en/1.4/topics/testing/#the-test-database),“为测试创建单独的空白数据库...测试数据库在所有测试执行完毕后被销毁“。如果你说预先存在的数据(测试运行之前)是问题,那么不,它不是。如果你说OP可能会终止测试来检查测试数据库,那当然会起作用,但是除了'IntegrityError'之外还会有什么信息? – supervacuo 2012-08-11 23:11:47

0

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

+0

这是一个很好的选择,绝对值得检查。 – 2012-08-11 22:03:50

+0

这并不能解释为什么如果将主键设置为auto_increment,主键不会增加。 – Risadinha 2016-10-06 19:21:39

0

你还没有发布完整的堆栈跟踪(请做!),但我认为错误是在创建UserProfile对象的线上。 Django文档explicitly sayAUTH_PROFILE_MODULE指定配置文件类将不会自动上添加新用户创建该类型的模型:

The method get_profile() does not create a profile if one does not exist. You need to register a handler for the User model's django.db.models.signals.post_save signal and, in the handler, if created is True, create the associated user profile:

所以,作为zifot暗示,有可能是在你的项目中一些其他的代码创建一个UserProfile。如果它这样做正确,只是从setUp删除您self.userProfile = models.UserProfile.objects.create(...线上,并通过

self.user.get_profile() 
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() 

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

这将是值得通过堆栈跟踪,我注意到两个插入语句。

这可能是一个迹象,我应该在其他地方移动此逻辑。 (我会这样做。)但遇到这个很有趣。