【问题标题】:How to test clean_<fieldname> method?如何测试 clean_<fieldname> 方法?
【发布时间】:2019-06-14 20:54:42
【问题描述】:

我尝试为我的 clean_ 方法编写一个测试。

这是我的测试代码

def test_clean_restraints(self):
    form = NewTaskForm(dict(restraints="90 20 <>"))
    form.clean_restraints()

在这一步我收到一个错误:

Error
Traceback (most recent call last):
  File "/home/user/django_projects/my_webservice/tasks/tests/test_forms.py", line 12, in test_clean_restraints
    form.clean_restraints()
  File "/home/user/django_projects/my_webservice/tasks/forms.py", line 22, in clean_restraints
    if self.cleaned_data.get('restraints') == '':
AttributeError: 'NewTaskForm' object has no attribute 'cleaned_data'

NewTaskForm 如下所示:

class NewTaskForm(ModelForm):
    class Meta:
        model = Task

    restraints = forms.CharField()
    region = forms.CharField()
    interactions = forms.CharField()

    def clean_restraints(self):
        if self.cleaned_data.get('restraints') == '':
            return self.cleaned_data.get('restraints')
        data = self.cleaned_data.get('restraints').strip().split('\n')
        regexp = re.compile(r'^(\d+)[\t ]+(\d+)[ \t]+([><]{2})?$')
        cleaned_data = []
        for i, line in enumerate(data):
            match = regexp.match(line)
            if not match:
                raise forms.ValidationError(f"Error in restraints in line {i + 1}")
            else:
                rst_1, rst_2, loop_type = match.groups()
                rst_1 = int(rst_1)
                rst_2 = int(rst_2)
                cleaned_data.append((rst_1, rst_2, loop_type))
        return cleaned_data

我正在使用 Django 2.1、python 3.7.1、PyCharm 2018.3.3 Professional 我试图在 PyCharm 的调试器下运行它,但事情变得疯狂。我收到不同的错误信息。看起来调试器在忽略断点的完整表单验证后停止了。我不知道发生了什么。

【问题讨论】:

  • 请注意,当您在 PyCharm 中调试表单清理方法时,您必须注意不要在调用清理方法本身之前的任何位置设置断点。那是因为调试器本身想要内省您的表单并将调用form.errors 来执行此操作(调用form.is_valid() 调用form.full_clean()...)所以clean 中的断点不再到达,因为form._errors 是已经有人了。

标签: django django-forms django-testing


【解决方案1】:

您应该测试验证过程的结果。

form = NewTaskForm(dict(restraints="90 20 <>"))
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['restraints'], "Error in restraints in line 1")

【讨论】:

  • 为什么?如果我的验证过程非常复杂怎么办?我不能把它分成更小的测试吗?
  • 如果您测试所有其他字段有效而只有一个字段无效,那么您实际上是在测试特定字段的验证。这就是你应该这样做的方式。使用一个特定的已知错误创建您的表单并测试该错误是否实际发生。这样您就可以测试整个验证过程的每一部分。
【解决方案2】:

好的,我发现了问题所在。

form.cleaned_datafull_clean() 中创建。不像我想的那样在构造函数中。它还调用每个clean_fieldname()。所以丑陋的解决方法是这样的:

def test_clean_restraints(self):
    initial_data = dict(restraints="90 20 <>")
    form = NewTaskForm()
    form.cleaned_data = initial_data
    form.clean_restraints()
    (...)

【讨论】:

  • 有一个更简单的解决方案:在受保护的_clean_restraints(self, cleaned_data) 方法中编写有效的验证,并从公共clean_restraints(self) 调用它 - 这样您就可以在没有“丑陋的解决方法”的情况下测试_clean_restraint()
猜你喜欢
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-01
  • 2015-05-29
  • 2012-04-06
  • 1970-01-01
  • 2019-06-04
相关资源
最近更新 更多