如何将unittests写入范围受限的Django CustomField?

2024-03-29 14:14:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我准备了WeekdayField,似乎和预期的一样。你知道吗

from django.db.models import PositiveSmallIntegerField
from django.core import validators
_ = lambda x: x

class WeekdayField(PositiveSmallIntegerField):
    MONDAY = 1
    TUESDAY = 2
    WEDNESDAY = 3
    THURSDAY = 4
    FRIDAY = 5
    SATURDAY = 6
    SUNDAY = 7

    DAY_OF_THE_WEEK = (
        (MONDAY, _('Monday')),
        (TUESDAY, _('Tuesday')),
        (WEDNESDAY, _('Wednesday')),
        (THURSDAY, _('Thursday')),
        (FRIDAY, _('Friday')),
        (SATURDAY, _('Saturday')),
        (SUNDAY, _('Sunday')),
    )

    default_validators = [
        validators.MinValueValidator(MONDAY),
        validators.MaxValueValidator(SUNDAY)
    ]

    def __init__(self, *args, **kwargs):
        kwargs['choices'] = WeekdayField.DAY_OF_THE_WEEK
        super(WeekdayField, self).__init__(*args, **kwargs)

当我开始为这个自定义字段编写unittests时,我发现了一些问题。你知道吗

我很惊讶,验证器只能由django表单调用。你知道吗

from django.contrib.humanize.templatetags.humanize import ordinal
from django.db import models
from django.forms.models import ModelForm
from django.test import TestCase
from services.fields import WeekdayField


class DayOfTheWeek(models.Model):
    day = WeekdayField()

class DayOfTheWeekForm(ModelForm):
    class Meta:
        model = DayOfTheWeek
        fields = ['day']

class WeekdayFieldTests(TestCase):

    def _check_day(self, day, expected):
        form = DayOfTheWeekForm({'day': day})
        self.assertEqual(
            form.is_valid(),
            expected,
            'There is no %s day of the week' % ordinal(day)
        )

    def test_7_days(self):
        days = range(WeekdayField.MONDAY, len(WeekdayField.DAY_OF_THE_WEEK)+1)
        for day in days:
            self._check_day(day, True)

    def test_no_0th_day_in_the_week(self):
        self._check_day(0,  False)

    def test_no_13th_day_in_the_week(self):
        self._check_day(13, False)

有没有更好的方法写这个?你知道吗


Tags: djangofromtestimportselfmodelsdefcheck
1条回答
网友
1楼 · 发布于 2024-03-29 14:14:55

重构之后,我有了这样的东西:

# -*- coding: utf-8 -*-
"""
This file contains custom definition of Django Model Fields
"""

from django.core.exceptions import ValidationError
from django.db.models import PositiveSmallIntegerField

_ = lambda x: x


class RangeValidator(object):
    """
    Validates whether proper value belongs to specified range
    """
    def __init__(self, bottom_limit, top_limit, message, code):
        self.bottom_limit = bottom_limit
        self.top_limit = top_limit
        self.message = message
        self.code = code

    def __call__(self, value):
        if not self.bottom_limit <= value <= self.top_limit:
            raise ValidationError(self.message, code=self.code)


class WeekdayField(PositiveSmallIntegerField):
    """
    Weekday field - simple Integer based field, to store number of the week.
    First day of the week is Monday, which is represented by number 1.
    """

    MONDAY = 1
    TUESDAY = 2
    WEDNESDAY = 3
    THURSDAY = 4
    FRIDAY = 5
    SATURDAY = 6
    SUNDAY = 7

    DAY_OF_THE_WEEK = (
        (MONDAY, _('Monday')),
        (TUESDAY, _('Tuesday')),
        (WEDNESDAY, _('Wednesday')),
        (THURSDAY, _('Thursday')),
        (FRIDAY, _('Friday')),
        (SATURDAY, _('Saturday')),
        (SUNDAY, _('Sunday')),
    )

    default_validators = [
        RangeValidator(
            bottom_limit=MONDAY,
            top_limit=SUNDAY,
            message=_(
                'Day number should be between {} and {}'.format(MONDAY, SUNDAY)
            ),
            code=_('wrong day number')
        )
    ]

我决定不使用validators.MinValueValidatorvalidators.MaxValueValidator,因为它们不会返回最佳错误消息。你知道吗

好消息是,测试文件中的新表单不需要测试该字段:)

以及测试:

# -*- coding: utf-8 -*-
from django.core.exceptions import ValidationError
from django.test import TestCase

from services.fields import WeekdayField


class WeekdayFieldTests(TestCase):

    def test_7_days(self):
        days = range(WeekdayField.MONDAY, len(WeekdayField.DAY_OF_THE_WEEK)+1)
        for day in days:
            field = WeekdayField()
            self.assertEqual(field.clean(day, None), day)

    def test_no_0th_day_in_the_week(self):
        field = WeekdayField()
        with self.assertRaisesMessage(
            ValidationError,
            expected_message=(
                u"Day number should be between 1 and 7"
            )
        ):
            field.clean(0, None)

    def test_no_13th_day_in_the_week(self):
        field = WeekdayField()
        with self.assertRaisesMessage(
            ValidationError,
            expected_message=(
                u"Day number should be between 1 and 7"
            )
        ):
            field.clean(13, None)

相关问题 更多 >