Django 更新表单的单元测试

Chr*_*phe 4 python forms django unit-testing django-tests

我不明白如何管理表单和相关单元测试的更新,我真的很感激一些建议 =)

\n

我有一个公司模型,以及相关的非常简单的 CompanyForm:

\n
class Company(models.Model):\n    """\n    Company informations\n    - Detailed information for display purposes in the application\n      but also used in documents built and sent by the application\n    - Mail information to be able to send emails\n    """\n    company_name = models.CharField("nom", max_length=200)\n    comp_slug = models.SlugField("slug")\n    logo = models.ImageField(upload_to="img/", null=True, blank=True)\n    use_groups = models.BooleanField("utilise les groupes", default=False)   # Company uses groups or not\n    rules = [("MAJ", "Majorit\xc3\xa9"), ("PROP", "Proportionnelle")]   # Default management rule\n    rule = models.CharField(\n        "mode de scrutin", max_length=5, choices=rules, default="MAJ"\n    )\n    upd_rule = models.BooleanField("choisir la r\xc3\xa8gle de r\xc3\xa9partition pour chaque \xc3\xa9v\xc3\xa9nement", default=False)     # Event rule might change from one to another or always use default\n    statut = models.CharField("forme juridique", max_length=50)\n    siret = models.CharField("SIRET", max_length=50)\n    street_num = models.IntegerField("N\xc2\xb0 de rue", null=True, blank=True)\n    street_cplt = models.CharField("compl\xc3\xa9ment", max_length=50, null=True, blank=True)\n    address1 = models.CharField("adresse", max_length=300)\n    address2 = models.CharField(\n        "compl\xc3\xa9ment d\'adresse", max_length=300, null=True, blank=True\n    )\n    zip_code = models.IntegerField("code postal")\n    city = models.CharField("ville", max_length=200)\n    host = models.CharField("serveur mail", max_length=50, null=True, blank=True)\n    port = models.IntegerField("port du serveur", null=True, blank=True)\n    hname = models.EmailField("utilisateur", max_length=100, null=True, blank=True)\n    fax = models.CharField("mot de passe", max_length=50, null=True, blank=True)\n    use_tls = models.BooleanField("authentification requise", default=True, blank=True)\n\n    class Meta:\n        verbose_name = "Soci\xc3\xa9t\xc3\xa9"\n        constraints = [\n            models.UniqueConstraint(fields=["comp_slug"], name="unique_comp_slug")\n        ]\n\n    def __str__(self):\n        return self.company_name\n\n    @classmethod\n    def get_company(cls, slug):\n        """ Retreive company from its slug """\n        return cls.objects.get(comp_slug=slug)\n\n\nclass CompanyForm(forms.ModelForm):\n    company_name = forms.CharField(label="Soci\xc3\xa9t\xc3\xa9", disabled=True)\n\n    class Meta:\n        model = Company\n        exclude = []\n
Run Code Online (Sandbox Code Playgroud)\n

视图也非常简单:

\n
@user_passes_test(lambda u: u.is_superuser or u.usercomp.is_admin)\ndef adm_options(request, comp_slug):\n    \'\'\'\n        Manage Company options\n    \'\'\'\n    company = Company.get_company(comp_slug)\n    comp_form = CompanyForm(request.POST or None, instance=company)\n\n    if request.method == "POST":\n        if comp_form.is_valid():\n            comp_form.save()\n\n    return render(request, "polls/adm_options.html", locals())\n
Run Code Online (Sandbox Code Playgroud)\n

这个视图工作正常,我可以更新信息(它实际上不用于创建,这是通过 Django 管理面板完成的)。

\n

不幸的是,我无法构建确保更新有效的单元测试!
\n我尝试了 2 种方法,但都不起作用。\n我的第一次尝试如下:

\n
class TestOptions(TestCase):\n    def setUp(self):\n        self.company = create_dummy_company("Soci\xc3\xa9t\xc3\xa9 de test")\n        self.user_staff = create_dummy_user(self.company, "staff", admin=True)\n        self.client.force_login(self.user_staff.user)\n\n    def test_adm_options_update(self):\n        # Load company options page\n        url = reverse("polls:adm_options", args=[self.company.comp_slug])\n        response = self.client.get(url)\n        self.assertEqual(response.status_code, 200)\n        self.assertContains(response, "0123456789")\n        self.assertEqual(self.company.siret, "0123456789")\n\n        # Options update\n        response = self.client.post(\n            reverse("polls:adm_options", args=[self.company.comp_slug]),\n            {"siret": "987654321"}\n        )\n        self.assertEqual(response.status_code, 200)\n        self.assertContains(response, "987654321")\n        self.assertNotContains(response, "0123456789")\n        self.assertEqual(self.company.siret, "987654321")\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,一切都很好,但最新的断言除外。看起来更新没有保存,实际情况并非如此。我之前尝试读取数据库,并将密钥存储在上下文中,但它保持不变。

\n

当我发现这个主题时,我正在寻找其他信息,所以我尝试了另一种方法来测试,即使该方法让我有点惊讶(我不知道视图是如何实际测试的)。
\n这是我的第二次尝试(setUp()保持不变):

\n
    def test_adm_options_update(self):\n        # Load company options page\n        url = reverse("polls:adm_options", args=[self.company.comp_slug])\n        response = self.client.get(url)\n        self.assertEqual(response.status_code, 200)\n        self.assertContains(response, "0123456789")         # this is the default value in tests for this field\n        self.assertEqual(self.company.siret, "0123456789")\n\n        # Options update\n        self.company.siret = "987654321"\n        comp_form = CompanyForm(instance=self.company)\n        self.assertTrue(comp_form.is_valid())\n        comp_form.save()\n        company = Company.get_company(self.company.comp_slug)\n        self.assertEqual(company.siret, "987654321")\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,表格只是空的!

\n

我可以考虑我的视图有效并继续,我的问题是我在另一个视图中存在错误,我想确保我可以构建测试以找出错误!

\n

非常感谢您的回答!

\n

编辑 - 8 月 30 日
\n以下建议,我尝试使用self.company.refresh_from_db(),但它没有改变结果。
\n尝试传递 中的所有字段,self.client.post()但一旦字段为空,它就会失败(\'无法将 None 编码为 POST 数据\'错误消息)
\n似乎我还创建了一个\'虚拟\'公司使用空的必填字段进行测试...无论如何它都有效。测试环境的问题?我改变了这一点,但我想知道问题是否出在其他地方......

\n

编辑 - 9 月 15 日
\n寻找可以为我提供新想法的人,请 =)

\n

为了确保我理解最新的命题,这里是测试的完整代码:

\n
def test_adm_options_update(self):\n    # Load company options page\n    url = reverse("polls:adm_options", args=[self.company.comp_slug])\n    response = self.client.get(url)\n    self.assertEqual(response.status_code, 200)\n    self.assertContains(response, "0123456789")\n    self.assertEqual(self.company.siret, "0123456789")\n\n    # Apply changes\n    company_data = copy.deepcopy(CompanyForm(instance=self.company).initial)\n    company_data[\'siret\'] = "987654321"\n    response = self.client.post(\n        reverse("polls:adm_options", args=[self.company.comp_slug]),\n        company_data,\n        )\n    self.company.refresh_from_db()\n    self.assertEqual(response.status_code, 200)\n    self.assertContains(response, "987654321")\n    self.assertNotContains(response, "0123456789")\n    self.assertEqual(self.company.siret, "987654321")\n
Run Code Online (Sandbox Code Playgroud)\n

这是创建用于测试的“虚拟”公司的函数:

\n
def create_dummy_company(name):\n    return Company.objects.create(\n        company_name=name,\n        comp_slug=slugify(name),\n        logo=SimpleUploadedFile(name=\'logo.jpg\', content=b\'content\', content_type=\'image/jpeg\'),\n        statut="SARL",\n        siret="0123456789",\n        address1="Rue des fauvettes",\n        zip_code="99456",\n        city=\'Somewhere\',\n        host="smtp.gmail.com",\n        port=587,\n        hname="test@polls.com",\n        fax="toto",\n    )\n
Run Code Online (Sandbox Code Playgroud)\n

bdb*_*dbd 6

refresh_from_db在这种情况下,一旦视图和表单完成更新对象,您需要使用“刷新”对象。这意味着当您当前断言时,您正在使用“旧快照”,因此self.company断言失败,因此您需要更新它:

        # Options update
        response = self.client.post(
            reverse("polls:adm_options", args=[self.company.comp_slug]),
            {"siret": "987654321"}
        )
        ...
        self.company.refresh_from_db()
        self.assertEqual(self.company.siret, "987654321")
Run Code Online (Sandbox Code Playgroud)

编辑

找到了一种方法来完成这项工作。由于表单要求您输入所有数据,因此您只需将公司实例传递到同一表单,并访问初始值(它将作为您的请求数据)。

然后,您可以根据需要进行修改,在本例中为siretlogo

from django.core.files.uploadedfile import SimpleUploadedFile

    def test(self):
        company_data = CompanyForm(instance=self.company).initial
        company_data['logo'] = SimpleUploadedFile(name='somefile', content=b'content', content_type='image/jpeg')
        company_data['siret'] = "987654321"

        response = self.client.post(
            reverse("polls:adm_options", args=[self.company.comp_slug]),
            company_data,
        )

        self.company.refresh_from_db()
        self.assertEqual(self.company.siret, "987654321")
Run Code Online (Sandbox Code Playgroud)

这有效,并以与您拥有的完全相同的模型传递给我。