如何测试Django MultiValueField的输入?

时间:2018-04-21 00:01:31

标签: python django

我目前正在Django项目中工作,该项目定义了一个自定义DateTimeField,如下所示(dashboard/forms/fields):

import pytz

from datetime import date, datetime

from django import forms
from django.core.exceptions import ValidationError

from dashboard.forms.widgets import DateTimeWidget


class DateTimeField(forms.MultiValueField):
    widget = DateTimeWidget

    DATE_FORMAT = '%B %d, %Y'
    TIME_FORMAT = '%I:%M %p'
    DATETIME_FORMAT = f'{DATE_FORMAT} {TIME_FORMAT}'

    def __init__(self, timezone_choices=None, timezone=None, **kwargs):
        fields = (forms.CharField(), forms.CharField(), forms.CharField())
        super().__init__(fields=fields, **kwargs)

        self.timezone_choices = timezone_choices
        self.timezone = timezone

    @property
    def timezone_choices(self):
        return self._timezone_choices

    @timezone_choices.setter
    def timezone_choices(self, value):
        self._timezone_choices = self.widget.timezone_choices = value

    @property
    def timezone(self):
        return self._timezone

    @timezone.setter
    def timezone(self, value):
        self._timezone = self.widget.timezone = value

    def compress(self, data_list):
        try:
            date, time, zone = data_list
            tz = pytz.timezone(zone)

            dt = datetime.strptime(f'{date} {time}', self.DATETIME_FORMAT)

            return tz.localize(dt)
        except ValueError:
            return None

此字段以SessionForm形式使用,如下所示:

class SessionForm(forms.ModelForm):
    class Meta:
        model = Session
        fields = [
            'scheduled_for',
        ]

    scheduled_for = DateTimeField(
        required=False,
        timezone_choices=Family.TIMEZONE_CHOICES
    )

此表单包含以下clean()方法,我想测试一下:

def clean(self):
    cleaned_data = super().clean()

    status = cleaned_data.get('status')
    location = cleaned_data.get('location')

    if status in [Session.SCHEDULED, Session.SCHEDULED_CALENDARED] and not cleaned_data.get('scheduled_for'):
        self.add_error(
            'scheduled_for',
            f"This field is required if the status is '{Session.SCHEDULED}' or '{Session.SCHEDULED_CALENDARED}'.")

    return cleaned_data

为此,我尝试编写以下测试:

class SessionCreateTest(TestCase):
    def test_scheduled_session_with_scheduled_time_and_expert_and_location_is_valid(self):
        scheduled_time = dateutil.parser.parse("5 January 2019 at 1:30 PM")
        date = scheduled_time.strftime(DateTimeField.DATE_FORMAT)
        time = scheduled_time.strftime(DateTimeField.TIME_FORMAT)
        zone = pytz.country_timezones('US')[20]     # 'America/Los_Angeles'
        scheduled_for = (date, time, zone)

        self.data.update(
            status=Session.SCHEDULED,
            scheduled_for=scheduled_for,
            expert=ExpertFactory().id,
            location=Session.AT_HOME)
        form = SessionForm(data=self.data)
        import ipdb; ipdb.set_trace()

不幸的是,当我进入调试器时,我发现表单仍有错误:

> /Users/kurtpeek/Documents/Dev/lucy2/lucy-web/dashboard/tests/test_sessions.py(666)test_scheduled_session_with_scheduled_time_and_expert_and_location_is_valid()
    665         import ipdb; ipdb.set_trace()
--> 666         self.assertTrue(form.is_valid())
    667 

ipdb> form.errors
{'scheduled_for': ["This field is required if the status is 'Scheduled' or 'Scheduled & Calendared'."]}

但是,如果我将此字段的输入传递给字段的compress()方法,则可能会将其解析为'正确地:

ipdb> field = DateTimeField()
ipdb> field.compress(scheduled_for)
datetime.datetime(2019, 1, 5, 13, 30, tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)

我不明白为什么这个测试没有通过?我怎么能打破这个呢?&#39;进一步?

1 个答案:

答案 0 :(得分:0)

我建议您将断点放在表单的 clean 方法内。检查 cleaned_data 字典中的 scheduled_for 的结构。它应该为您提供测试所需的答案。