首页 > 解决方案 > django ValidationError 未在测试中引发但在 shell 中引发

问题描述

我在下面定义了一个模型,它在 clean() 方法中调用管理器。

from django.core.exceptions import ValidationError
from django.db import models
from re import sub

class Vessel(models.Model):
    name = models.CharField(max_length=50)
    stripped_name = models.CharField(
        max_length=50, unique=True, null=True, blank=True
    )

    def save(self, *args, **kwargs):
        stripped_name = sub(r'\s+', ' ', str(self.name).upper().strip())
        stripped_name = sub(r'^M[^a-zA-Z]*V\s*', '', stripped_name)
        stripped_name = sub(r'[^\w]', '', str(stripped_name).upper())
        self.stripped_name = stripped_name
        super().save(*args, **kwargs)

    def clean(self):
        stripped_name = sub(r'\s+', ' ', str(self.name).upper().strip())
        stripped_name = sub(r'^M[^a-zA-Z]*V\s*', '', stripped_name)
        stripped_name = sub(r'[^\w]', '', str(stripped_name).upper())
        if Vessel.objects.all().filter(stripped_name = stripped_name).exists():
            return ValidationError("Vessel name exists.")

在新刷新的 shell 中,IntegrityError 被很好地提升。

>>> from my_random_app.models import Vessel
>>> vessel = Vessel(name='PM Hayabusa')
>>> vessel.save()
>>> vessel = Vessel(name=' M/V PM-HAYABUSA')
>>> vessel.save() # Raises IntegrityError

甚至 ValidationError 也被很好地提出。

>>> from my_random_app.models import Vessel
>>> vessel = Vessel(name='PM Hayabusa')
>>> vessel.save()
>>> vessel = Vessel(name=' M/V PM-HAYABUSA')
>>> vessel.clean() # Raises ValidationError

但在自动化测试中,不会引发 ValidationError。

from django.core.exceptions import ValidationError
from django.db.utils import IntegrityError
from django.test import TestCase

from my_random_app.models import Vessel

class  VesselTest(TestCase):

    def setUp(self):
        pass

    def test_a(self):
        vessel = Vessel(name='PM Hayabusa')
        vessel.save()
        vessel = Vessel(name=' M/V PM-HAYABUSA')
        self.assertRaises(IntegrityError, vessel.save)

    def test_b(self):
        vessel = Vessel(name='PM Hayabusa')
        vessel.save()
        vessel = Vessel(name=' M/V PM-HAYABUSA')

        # This line FAILS!
        self.assertRaises(ValidationError, vessel.clean)

这与我在 clean() 方法中调用管理器的方式有关吗?为什么在 shell 中出现验证错误,但在测试中没有出现?

标签: pythondjango

解决方案


你所做的几乎是完美的:)

ValidationError 是一个异常,需要引发一些事情,而不是打算返回。

如果您更换return->raise您的问题将得到解决。

        if Vessel.objects.all().filter(stripped_name = stripped_name).exists():
            raise ValidationError("Vessel name exists.")

当您在 shell clean 方法中执行此操作时,会返回错误,因此您认为它可以正常工作,但实际上并非如此。

>>> from my_random_app.models import Vessel
>>> vessel = Vessel(name='PM Hayabusa')
>>> vessel.save()
>>> vessel = Vessel(name=' M/V PM-HAYABUSA')
>>> vessel.clean() # Returns ValidationError
ValidationError(['Vessel name exists.'])

当它升起时,它变成了流动的:

>>> from my_random_app.models import Vessel
>>> vessel = Vessel(name='PM Hayabusa')
>>> vessel.save()
>>> vessel = Vessel(name=' M/V PM-HAYABUSA')
>>> vessel.clean()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/***/**/myapp/models.py", line 25, in clean
    raise ValidationError("Vessel name exists.")
django.core.exceptions.ValidationError: ['Vessel name exists.']

推荐阅读