【问题标题】:How to unit test a blank field form in Django?如何在 Django 中对空白字段表单进行单元测试?
【发布时间】:2021-09-17 07:04:00
【问题描述】:

我花了很多时间来设置一些单元测试,其中一个问题是设置了一些我定义为可空和可空白的字段。放置虚拟值不是问题,但我想知道:如何处理需要为空白的字段,尤其是数字?
让我以我的代码摘录为例。

型号:

class Company(models.Model):
    company_name = models.CharField("nom", max_length=200)
    comp_slug = models.SlugField("slug")
    logo = models.ImageField(upload_to="img/", null=True, blank=True)
    street_num = models.IntegerField("N° de rue", null=True, blank=True)
    street_cplt = models.CharField("complément", max_length=50, null=True, blank=True)
    address = models.CharField("adresse", max_length=300)

    @classmethod
    def get_company(cls, comp_slug):
        return cls.objects.filter(comp_slug=comp_slug).get()

形式:

class CompanyForm(forms.ModelForm):
    company_name = forms.CharField(label="Société", disabled=True)

    class Meta:
        model = Company
        exclude = []

观点:

def adm_options(request, comp_slug):
    """
    Manage Company options
    """
    company = Company.get_company(comp_slug)
    comp_form = CompanyForm(request.POST or None, instance=company)

    if request.method == "POST":
        if comp_form.is_valid():
            comp_form.save()

    return render(request, "polls/adm_options.html", locals())

一个简单的单元测试:

def create_dummy_company(name):
    return Company.objects.create(
        company_name=name,
        comp_slug=slugify(name),
        logo=SimpleUploadedFile(name='logo.jpg', content=b'content', content_type='image/jpeg'),
        street_num=1,
        street_cplt='',
        address='dummy address'
    )


class TestOptions(TestCase):

    def test_adm_options_update(self):
        self.company = create_dummy_company("Test company")
        url = reverse("polls:adm_options", args=[self.company.comp_slug])
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        self.company.address = 'new address'
        response = self.client.post(
            reverse("polls:adm_options", args=[self.company.comp_slug]),
            self.company.__dict__,
        )
        self.company.refresh_from_db()
        self.assertEqual(response.status_code, 200)
        self.assertEqual(self.company.address, "new address")

关键部分是在更新后发布表单。我遇到的不同案例如下:

  1. 上面写的测试没问题。

  2. 如果我省略了street_numstreet_cplt,帖子会引发:

    TypeError:无法将 None 编码为 POST 数据。您的意思是传递一个空字符串还是省略该值?

    如果我省略logo,它会引发:

    ValueError: 'logo' 属性没有与之关联的文件。

    这是我的主要问题,在我看来,这些字段应该保持空白且没有错误。

  3. 那么,数字字段呢?如何将street_num 设置为空白?如果我尝试street_num='',它会引发:

    ValueError: int() 以 10 为底的无效文字:''

那么我该如何处理这个问题,构建一个单元测试来检查我是否可以发布一个没有设置为 null=True, blank=True 的每个字段的值的表单?

【问题讨论】:

标签: python django unit-testing django-forms nullable


【解决方案1】:

TypeError:无法将键“street_num”的无编码为 POST 数据。您的意思是传递一个空字符串还是省略该值?

ValueError: int() 以 10 为底的无效文字:''

content_type='multipart/form-data'(默认)不支持None,所以排除它。

comp_data = {k: v for k, v in self.company.__dict__.items() if v is not None}

content_type='application/json' 不支持ImageField 没有太多麻烦。
除了request.POST,您还需要处理request.body


ValueError: 'logo' 属性没有与之关联的文件。

您需要手动排除<ImageFieldFile: None>

if not self.company.logo:
    del comp_data['logo']

解决方案作为代码的一部分:

comp_data = {k: v for k, v in self.company.__dict__.items() if v is not None}  # Add this
if not self.company.logo:                                                      # Add this
    del comp_data['logo']                                                      # Add this
response = self.client.post(
    reverse("polls:adm_options", args=[self.company.comp_slug]),
    # self.company.__dict__,  # Replace this
    comp_data,                # with this
)

【讨论】:

  • 非常感谢!它使用这种方法,测试通过。我只是想知道......恐怕我的观点实际上不起作用(不再?不确定,但我认为它曾经有效,我需要退回到我的项目),我是否应该考虑同样的方法从我的表单中实际更新数据?
  • 您的视图功能看起来不错。您可以提出其他问题并提供更多详细信息。
猜你喜欢
  • 2011-03-10
  • 2013-05-08
  • 2013-09-29
  • 2018-09-27
  • 2016-12-16
  • 2017-04-12
  • 2011-01-29
  • 2014-09-21
  • 2013-06-14
相关资源
最近更新 更多