如何在限制范围内对Django Custom Field进行单元测试?

时间:2014-12-14 11:38:22

标签: python django unit-testing django-models

我准备了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)

当我开始为这个自定义字段编写单元测试时,我发现了问题。

我很惊讶,验证器只能通过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)

有没有更好的方法来写这个?

1 个答案:

答案 0 :(得分:0)

重构后,我有类似的东西:

# -*- 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,因为它们没有返回最佳错误消息。

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

并测试:

# -*- 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)