Как провести модульное тестирование формы с чистым полем в Django?

Я потратил довольно много времени на создание некоторых модульных тестов, и одной из проблем было задание некоторых полей, которые я определяю как nullable и blankable. Подстановка фиктивных значений не была проблемой, но я задался вопросом: как быть с полями, которые должны быть пустыми, в частности, для чисел?
. Позвольте мне написать в качестве примера выдержку из моего кода.

Модель:

class Company(models.Model):
    company_name = models.CharField("nom", max_length=200)
    comp_slug = models.SlugField("slug")
    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)

Форма:

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),
        street_num=1,
        street_cplt='',
        address='dummy address'
    )

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)

Конечно, ключевым моментом является размещение формы после обновления. Различные случаи, с которыми я столкнулся, были следующими:

  • Нет проблем с тестом, как написано выше
  • Если я опускаю одно из полей (street_num или street_cplt), пост поднимается TypeError: Cannot encode None as POST data. Did you mean to pass an empty string or omit the value? Это может быть основной проблемой, поскольку оба поля могут быть пустыми
  • .
  • Тогда как быть с числовыми полями? Как я могу установить street_num на пустое место? Если я пытаюсь street_num='', то возникает ошибка Value: ValueError: invalid literal for int() with base 10: ''

Итак, как я могу справиться с этим, например, создать модульный тест, который проверяет, что я могу опубликовать форму без значений для каждого отдельного поля, установленных в null=True, blank=True?

TypeError: Cannot encode None for key 'street_num' as POST data. Вы хотели передать пустую строку или опустить значение?

.

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.body в дополнение к request.POST.


Ошибка в значении: Атрибут '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
)
Вернуться на верх