【问题标题】:Testing when a ValidationError is raised在引发 ValidationError 时进行测试
【发布时间】:2018-09-24 05:57:16
【问题描述】:

我是编程和 Django 的新手。我正在尝试测试我的一个功能以确保引发验证错误。测试确认错误已引发,但也表示测试失败。这怎么可能?

**models.py**
def check_user_words(sender, instance, **kwargs):
    for field in instance._meta.get_fields():
        #field_name = getattr(instance, field.attname)
        if (isinstance(field, models.CharField) and
            contains_bad_words(getattr(instance, field.attname))):
            raise ValidationError("We don't use words like '{}' around here!".format(getattr(instance, field.attname)))

#tests.py
from __future__ import unicode_literals
import datetime
from django.test import TestCase
from django.utils import timezone
from django.test import TestCase
from django.urls import reverse
from .models import Question, Choice, contains_bad_words, check_user_words
from django.core.exceptions import ValidationError


def create_question(question_text, days):
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)


class ContainsBadWordsTests(TestCase):
    def test_check_user_words(self):
    question = create_question(question_text="What a minute bucko", days=1)
    with self.assertRaises(ValidationError):
        check_user_words(question)
        question.full_clean()

#after running python manage.py test polls
......
raise ValidationError("We don't use words like '{}' around here!".format(getattr(instance, field.attname)))
ValidationError: [u"We don't use words like 'What a minute bucko' around here!"]

models.py 我如何导入

from __future__ import unicode_literals .... (and others)

filepath = "polls/static/polls/blacklist.yaml"
config = yaml_loader(filepath)
blacklist = [word.lower() for word in config['blacklist']]

def contains_bad_words(user_input_txt):
""" remove punctuation from text
    and make it case-insensitive"""
    user_typ = user_input_txt.encode()
    translate_table = maketrans(string.punctuation, 32 * " ")
    words = user_typ.translate(translate_table).lower().split()
    for bad_word in blacklist:
        for word in words:
            if word == bad_word:
                return True
    return False

@receiver(pre_save)
def check_user_words(sender, instance, **kwargs):
    for field in instance._meta.get_fields():
        if (isinstance(field, models.CharField) and
            contains_bad_words(getattr(instance, field.attname))):
        raise ValidationError("We don't use words like '{}' around here!".format(getattr(instance, field.attname))) 

【问题讨论】:

  • 实际测试失败的原因是什么?您可能会检查您是否指的是相同的ValidationError 类型
  • 除了我所展示的,这就是所有的展示:
  • 在 0.061 秒内运行 11 次测试失败 (errors=1) 正在销毁别名“default”的测试数据库...
  • 所以测试应该引发异常,我无法弄清楚为什么测试会失败。
  • 请告诉我们你是如何在测试中导入ValidationError的。

标签: django python-2.7 testing validationerror


【解决方案1】:

我们需要查看更多您的代码(特别是 create_question() 以及 check_user_words 如何连接到信号)才能确定,但​​我认为问题在于您使用 post_save 信号处理程序来执行 @ 987654325@。

如果是这种情况,那么您的测试失败的原因是create_question() 将导致post_save 信号触发,并且check_user_words() 将立即执行 - 即,之前 with self.assertRaises 上下文,因此您的测试失败。

如果是这种情况,那么试试这个:

def test_check_user_words(self):
    with self.assertRaises(ValidationError):
        create_question(question_text="What a minute bucko", days=1)

该测试现在应该通过了,因为一旦您尝试创建问题,就会引发验证错误。

但是请注意,在信号中执行此操作将导致在尝试保存对象时出现未捕获的异常。根据您的用例,您最好在模型本身 (see docs here) 的 clean() 方法中执行此操作,因为这会导致在模型表单等上报告适当的错误:

def clean(self):
    for field in instance._meta.get_fields():    
        if (isinstance(field, models.CharField) and contains_bad_words(getattr(instance, field.attname))):
            raise ValidationError("We don't use words like '{}' around here!".format(getattr(instance, field.attname)))

(然后删除您的信号处理程序)。然后您可以使用以下方法进行测试:

q = create_question(question_text="What a minute bucko", days=1)
with self.assertRaises(ValidationError):
    q.clean()

【讨论】:

  • 你的直觉是对的!谢谢你!唯一的问题是它是 pre_save,而不是 post_save。我在上面添加了更多我的 models.py 代码。如果我的意图是预先保存并且我真正测试的是 check_user_words() 函数是否有效(抛出异常),那么使用上面的建议是否仍然正确?
  • 是的,pre_save() 也是如此。该代码将在您尝试创建问题后立即执行,因此我在上面发布的代码仍然可以验证验证是否发生。也就是说,我已经编辑了答案以提出一种不使用信号的替代方法。
  • 非常感谢!!如果我想在保存之前使用 pre_save 信号检查和验证某些条件,那么合适的方法是什么?在 models.py 中定义了我的两个类后,我有以下代码:
  • pre_save.connect(check_user_words, sender=Question)
  • pre_save.connect(check_user_words, sender=Choice)
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 2021-05-25
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-18
  • 2019-01-26
相关资源
最近更新 更多