在Django中进行TDD,如何对我的modelform进行单元测试?

4
我是TDD的新手,正在尝试在Django项目中应用TDD实践。
基于伦敦学派的TDD工作流程,我从外向内逐层进行开发,包括视图层、表单层和模型层。在表单层,我计划构建一个模型表单,并编写一些自定义的验证方法。我认为,根据TDD原则,我只需要测试我的自定义方法,而不触及以下内容:
- 由Django提供的整个ModelForm逻辑,因为这是一个经过充分测试的依赖项。 - 下层的模型层,因为它还不存在。
但是我该如何做呢?例如,对于以下模型表单:
from django import forms
from app import models

class MyModelForm(forms.ModelForm):

    class Meta:
        model = models.MyModel
        fields = ("field1", "field2")

    def clean_field1(self):
        # custom cleaning logic

    def clean_field2(self):
        # custom cleaning logic

    def clean(self):
        # custom cleaning logic
  • How can I (or should I) mock MyModel? I've come up with

    @patch("app.forms.MyModelForm._meta.model")
    class FormTest(TestCase):
        #...
    

    But maybe it's a little bit insane? And I'm not sure how well the Mock object will work with ModelForm internal logic. For one thing, all form fields are gone, aren't they?

  • How can I unit test these custom methods? By setting self.cleaned_data manually?


对被测试单元进行修补似乎是一个不好的主意。但是你能否更清楚地描述一下你想要测试的行为呢? - jonrsharpe
@jonrsharpe您好,感谢您的帮助。您认为这里的MyModel属于被测试单元吗?它不是更低级别的依赖项(意味着表单层依赖于模型层)吗? - Naitree
1个回答

2
在使用像Django这样的框架编写单元测试是很棘手的。问题在于,Django的设计非常紧密地将模型和表单耦合在一起。在此处所说的耦合意味着表单期望模型中存在特定的字段,例如。
考虑到模型很少具有任何逻辑本身,通常只是字段的定义,我认为将表单与模型一起测试而不进行模拟更为实际。你在表单中定义的逻辑的测试大多数情况下只会依赖于字段的定义。
但回到你的问题。
你可以成为一个纯粹主义者并模拟模型。为了独立测试表单,您需要以稍微不同的方式模拟模型。您需要使用另一个测试模型,该测试模型具有该表单可以处理的模型的最小定义。这个测试模型在表单和模型之间建立了某种契约。也就是说,这个表单希望模型具有哪些字段。然后在测试中,您应该使用测试模型模拟表单中的模型。
您可以使用渐进式的TDD实践来做到这一点。也就是说,从包含一个字段的表单开始测试,并创建(初始为空的)测试模型,逐步添加字段并在表单中创建它们的测试。
当然,您仍需要进行集成测试(或多个测试)以检查您的表单与真实模型的配合情况。
还有一个重要的点。您是正确的,不应该测试Django提供的逻辑。但这并不意味着您的测试不能依赖它并使用它。
对于您自己的代码也是如此。表单的测试不应直接测试您的模型,但从实际角度来看,它可以依赖于真实的模型(前提是模型逻辑本身也在自己的测试中得到了测试)。有人会认为这不是一个纯粹的单元测试,但这是您使用面向有期限完美主义者的Web框架所付出的代价。

谢谢,我同意你关于模型表单测试可以依赖于测试模型的观点。我的策略是,在进行模型表单的TDD时,首先为该模型表单创建一个占位符模型。然后只为自定义验证方法编写测试。如果我的任何自定义验证方法需要数据,这些数据应该由Django的ModelForm逻辑提供(例如cleaned_data),我会在我的测试用例中手动提供它们。在表单层完成后,我进入模型层,并通过相同的TDD工作流填充占位符模型。 - Naitree

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接