如何在 Django 中对空白字段表单进行单元测试?
How to unit test a blank field form in Django?
我花了很多时间来设置一些单元测试,其中一个问题是我定义为可空和可空白的一些字段的设置。放置虚拟值不是问题,但我想知道:如何处理需要留空的字段,尤其是数字?
让我写一个我的代码摘录作为例子。
型号:
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")
关键部分是post更新后的表格。我遇到的不同案例如下:
上面写的测试没问题
如果我省略 street_num
或 street_cplt
,post 加注:
TypeError: Cannot encode None as POST data. Did you mean to pass an empty string or omit the value?
如果我省略 logo
,它会引发:
ValueError: The 'logo' attribute has no file associated with it.
这是我的主要问题,因为在我看来,这些字段应该保持空白且没有错误。
那么,数字字段呢?如何将 street_num
设置为空白?如果我尝试 street_num=''
,它会引发:
ValueError: invalid literal for int() with base 10: ''
那么我该如何处理,构建一个单元测试来检查我是否可以 post 一个没有每个字段值的表单设置为 null=True, blank=True
?
TypeError: Cannot encode None for key 'street_num' as POST data. Did you mean to pass an empty string or omit the value?
ValueError: invalid literal for int() with base 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: The 'logo' attribute has no file associated with it.
您需要手动排除 <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
)
我花了很多时间来设置一些单元测试,其中一个问题是我定义为可空和可空白的一些字段的设置。放置虚拟值不是问题,但我想知道:如何处理需要留空的字段,尤其是数字?
让我写一个我的代码摘录作为例子。
型号:
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")
关键部分是post更新后的表格。我遇到的不同案例如下:
上面写的测试没问题
如果我省略
street_num
或street_cplt
,post 加注:TypeError: Cannot encode None as POST data. Did you mean to pass an empty string or omit the value?
如果我省略
logo
,它会引发:ValueError: The 'logo' attribute has no file associated with it.
这是我的主要问题,因为在我看来,这些字段应该保持空白且没有错误。
那么,数字字段呢?如何将
street_num
设置为空白?如果我尝试street_num=''
,它会引发:ValueError: invalid literal for int() with base 10: ''
那么我该如何处理,构建一个单元测试来检查我是否可以 post 一个没有每个字段值的表单设置为 null=True, blank=True
?
TypeError: Cannot encode None for key 'street_num' as POST data. Did you mean to pass an empty string or omit the value?
ValueError: invalid literal for int() with base 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: The 'logo' attribute has no file associated with it.
您需要手动排除 <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
)