在Django管理后台对内联进行单元测试验证

4 投票
1 回答
3771 浏览
提问于 2025-04-18 00:28

我在Django的后台管理系统中给一个内嵌表单添加了一些验证,目的是如果模型实例中的某个字段不存在,就不让这个内嵌表单被保存。我不想在没有截止日期的情况下再添加其他截止日期:

class DeadlineInlineFormset(forms.models.BaseInlineFormSet):
    def clean(self):
        super(DeadlineInlineFormset, self).clean()
        # make sure deadline is set
        if not self.instance.deadline:
            raise ValidationError(_("Doesn't validate"))


class DeadlineInline(admin.StackedInline):
    model = AdditionalDeadline
    formset = DeadlineInlineFormset


class GrantAdmin(admin.ModelAdmin):
    ...
    inlines = [DeadlineInline]
    ...

这个功能运行得不错,但我在进行单元测试时遇到了麻烦。目前我有:

class GrantAdminTestCase(TestCase):

    fixtures = [...]

    def test_forms(self):
        # create the form from a model instance.
        # it should validate but it doesn't
        g = Grant.objects.first()
        form = GrantAdminForm(instance=g)
        self.assertEqual(form.is_valid(), True)

        # remove deadline and add additional deadlines
        # It shouldn't be valid because deadline is None
        g.deadline = None
        g.additional_deadlines.add(
            Deadline(deadline=datetime.now())
        )
        self.assertEqual(form.is_valid(), False)

第一个断言失败了,尽管模型实例是有效的。第二个断言通过了,但其实不应该通过,因为现在应该是无效的。所以肯定是哪里出了问题。

我也不太确定这样做是否正确。把验证放在模型里会不会更简单?或者放在表单里,而不是放在表单集里呢?

编辑:之前有很多地方是错的,我改了一些东西,但还是不行:

def test_forms(self):
    g = Grant.objects.first()
    form = GrantAdminForm(model_to_dict(g))
    self.assertEqual(form.is_valid(), True)

    DeadlineFormSet = inlineformset_factory(Grant, Deadline)

    # should be invalid
    g.deadline = None
    g.additional_deadlines.add(Deadline(deadline=datetime.now()))
    formset = DeadlineFormSet(instance=g)
    self.assertEqual(formset.is_valid(), False)

    # should be valid
    g = Grant.objects.first()
    formset = DeadlineFormSet(instance=g)
    self.assertEqual(formset.is_valid(), True)

前两个断言通过了,但最后一个没有。

1 个回答

10

这段内容让我找到了答案,答案是:

class GrantAdminTestCase(TestCase):
    fixtures = [
        'grants/grant_config',
        'grants/grants',
    ]

    def setUp(self):
        self.g = Grant.objects.first()

        self.DeadlineFormSet = inlineformset_factory(
            Grant, Deadline, formset=DeadlineInlineFormset)

        self.data = {
            'additional_deadlines-INITIAL_FORMS': 0,
            'additional_deadlines-MAX_NUM_FORMS': 1000,
            'additional_deadlines-TOTAL_FORMS': 1,
            'additional_deadlines-0-deadline': date.today(),
            'additional_deadlines-0-grant': '2',
            'additional_deadlines-0-id': '',
        }

    def test_formset_is_valid_if_deadline_exists(self):
        formset = self.DeadlineFormSet(self.data, instance=self.g)
        self.assertEqual(formset.is_valid(), True)

    def test_formset_is_invalid_if_deadline_doesnt_exist(self):
        # formset should be invalid if there is an additional deadline
        # and no main deadline
        self.g.deadline = None
        formset = self.DeadlineFormSet(self.data, instance=self.g)
        self.assertEqual(formset.is_valid(), False)

    def test_formset_is_valid_if_deadline_blank(self):
        # formset should still be valid if deadline is blank
        # (it's not saved)
        self.data['additional_deadlines-0-deadline'] = ''
        formset = self.DeadlineFormSet(self.data, instance=self.g)
        self.assertEqual(formset.is_valid(), True)

    def test_formset_is_invalid_if_additional_deadlines_earlier(self):
        # formset should be invalid if any additional deadlines are earlier
        # than the main deadline
        self.g.deadline = date.today()
        yesterday = date.today() - timedelta(days=1)
        self.data['additional_deadlines-0-deadline'] = yesterday
        formset = self.DeadlineFormSet(self.data, instance=self.g)
        self.assertEqual(formset.is_valid(), False)

撰写回答