【问题标题】:Fail on Testing IntegrityError UNIQUE constraint测试 IntegrityError UNIQUE 约束失败
【发布时间】:2016-12-22 17:41:23
【问题描述】:

我对电子邮件和商店有一个 unique_together 约束。我使用以下代码来测试唯一约束。我希望通过 assertRaise 的测试,但结果却相反。我在这里缺少什么?

from django.db.backends.sqlite3.base import IntegrityError

class TestUserModel(TestCase):
    def setUp(self):
        self.store1 = Store.objects.create(name='store1')
        self.store2 = Store.objects.create(name='store2')

    def multiple_user_with_same_email_and_store(self):
        data1 = dict(email="abcd@gmail.com", password="a", store=self.store1)
        data2 = dict(email="abcd@gmail.com", password="abc", store=self.store1)
        self.user1 = User.objects.create(**data1)
        user2 = User(**data2)
        self.assertRaises(IntegrityError, user2.save)

追溯

    Creating test database for alias 'default'...
E
======================================================================
ERROR: multiple_user_with_same_email_and_store (user.tests.test_models.TestUserModel)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ram/nk/project/helper/helper/user/tests/test_models.py", line 25, in multiple_user_with_same_email_and_store
    self.assertRaises(IntegrityError, user2.save)
  File "/usr/lib/python2.7/unittest/case.py", line 473, in assertRaises
    callableObj(*args, **kwargs)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 734, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 762, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 846, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 885, in _do_insert
    using=using, raw=raw)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/query.py", line 920, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 974, in execute_sql
    cursor.execute(sql, params)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 318, in execute
    return Database.Cursor.execute(self, query, params)
IntegrityError: UNIQUE constraint failed: user_user.email, user_user.store_id


    ----------------------------------------------------------------------
    Ran 1 test in 0.003s

    FAILED (errors=1)

User模型扩展了AbstractUser(User处没有添加其他),如下

class AbstractUser(auth_models.AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(_('email address'))
    store = models.ForeignKey(Store, verbose_name=_('Store Name'), null=True)
    first_name = models.CharField(_('First name'), max_length=255, blank=True)
    last_name = models.CharField(_('Last name'), max_length=255, blank=True)
    is_staff = models.BooleanField(
            _('Staff status'), default=False,
            help_text=_('Designates whether the user can log into this admin '
                        'site.'))
    is_active = models.BooleanField(
            _('Active'), default=True,
            help_text=_('Designates whether this user should be treated as '
                        'active. Unselect this instead of deleting accounts.'))
    date_joined = models.DateTimeField(_('date joined'),
                                       default=timezone.now)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['store']

    class Meta:
        abstract = True
        verbose_name = _('User')
        verbose_name_plural = _('Users')
        unique_together = ('email', 'store')

和用户管理器

class UserManager(auth_models.BaseUserManager):
    def create_user(self, store, email, password=None, **extra_fields):
        """
        Creates and saves a User with the given email and
        password.
        """
        now = timezone.now()
        if not email:
            raise ValueError('The given email must be set')
        email = UserManager.normalize_email(email)
        try:
            with transaction.atomic():
                store, created = Store.objects.get_or_create(name=store)
                user = self.model(email=email, store=store, is_staff=False, is_active=True, is_superuser=False,
                        last_login=now, date_joined=now, **extra_fields)
                user.set_password(password)
                user.save(using=self._db)
        except Error as e:
            logging.ERROR(e)
            raise Error("Internal Error: Unable to create user")
        return user

    def create_superuser(self, store, email, password, **extra_fields):
        u = self.create_user(store, email, password, **extra_fields)
        u.is_staff = True
        u.is_active = True
        u.is_superuser = True
        u.save(using=self._db)
        return u

    def create_staffuser(self, store, email, password, **extra_fields):
        u = self.create_user(store, email, password, **extra_fields)
        u.is_staff = True
        u.is_active = True
        u.is_superuser = False
        u.save(using=self._db)
        return u

版本:1.8

【问题讨论】:

  • 能否请您显示您的User 模型的定义(字段,如果有,init 方法)以及完整的错误堆栈跟踪
  • unique_together 应该是元组的元组(在这种情况下,它会检查电子邮件本身是否唯一并且存储本身是否唯一),请参阅docs.djangoproject.com/en/1.10/ref/models/options/…,但它没有解释为什么它不是t 在预期的线路上失败(尽管在这里完整的错误回溯会有所帮助)
  • 在测试中,IntegrityError是从哪里导入的?
  • 我怀疑某种包装器 (django.db.utils.IntegrityError) 或导入 mixup,并将使用 self.assertRaises 作为上下文管理器进行调试 - with self.assertRaises(Exception) as raised: user2.save() 后跟 self.assertEqual(IntegrityError, type(raised.exception))跨度>
  • 感兴趣的类型不是raised而是raised.exception,它是self.assertEqual(In‌​tegrityError, type(raised.exceptio‌​n))而不是self.assertEqual(In‌​tegrityError, raised.exception)

标签: django unit-testing django-models


【解决方案1】:

所以错误是在正确的行(assertRaises)引发的,但我怀疑这里有两种不同的IntegrityError 类在起作用——一种是由测试导入的,另一种是引发的由数据库后端。

例如:django.db.backends.postgresql.base.IntegrityErrordjango.db.backends.sqlite3.base.IntegrityError 不同。最重要的是,还有 Django 异常包装器django.db.utils.IntegrityError

可以通过使用self.assertRaises 作为上下文管理器来调试和验证该问题:

with self.assertRaises(Exception) as raised:  # top level exception as we want to figure out its exact type
    user2.save()
self.assertEqual(IntegrityError, type(raised.exception))  # if it fails, we'll get the correct type to import

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2018-11-17
    • 2021-12-09
    相关资源
    最近更新 更多