Drakonn
@Drakonn
Инженер-программист

Django. Form tests. Как работает тест?

Здравствуйте. Пишу интеграционный тест формы.
Есть форма с inline formset, которая работает корректно, однако тесты на добавление элементов не проходят (post запросы). Тесты завершаются ошибкой
Данные управляющей формы отсутствуют или были повреждены
. При обращении через браузер проблем нет.
Исходные коды

Код формы
class CompanyForm(forms.ModelForm):
    """ Форма регистрации новой компании """
    name = forms.CharField(required=True, label='Название компании', 
        widget=forms.TextInput(attrs={'placeholder': 'Сеть салонов Beauty Empire'}))
    description = forms.CharField(required=True, label='Описание', 
        widget=forms.TextInput(attrs={'placeholder': 'Оказываемые услуги, описание'}))
    logo_url = forms.URLField(required=False, label='Логотип, ссылка http://')

    class Meta:
        """ Параметры """
        model=Companies
        fields=['name', 'description', 'logo_url']

Код контроллера формы
class CompanyRegistration(LoginRequiredMixin, CreateView):
    """ Вид формы регистрации новой компании """
    model = Companies
    template_name = 'companies_app/forms/company/company_add.html'
    form_class = CompanyForm
    success_url = None

    def get_context_data(self, **kwargs):
        data = super(CompanyRegistration, self).get_context_data(**kwargs)
        ContactFormSetInstance = formset_factory(form=ContactInfoEditForm,
                                                 formset=BaseContactInfoFormSet, extra=5)
        if self.request.POST:
            data['contacts_formset'] = ContactFormSetInstance(
                self.request.POST)
        else:
            data['contacts_formset'] = ContactFormSetInstance()
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        contacts_formset = context['contacts_formset']
        with transaction.atomic():
            if form.is_valid() and contacts_formset.is_valid():
                profile = get_object_or_404(
                    Profiles, user__id=self.request.user.id)
                company = form.save(commit=False)
                company.owner = profile
                company.save()
                update_contacts_data(
                    contacts_formset, CompanyContactsManager(company))
        return super(CompanyRegistration, self).form_valid(form)

    def get_success_url(self):
        return reverse_lazy('dashboard_company', kwargs={'pk': self.object.pk})

Код шаблона
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% block title %}{{ title }}{% endblock %}

{% block styleblock%}
  <link href="{% static 'css/profile_glass_morphism.css' %}" rel="stylesheet"/> 
{% endblock%}

{% block content %}

<form method="post" class="glass-block p-3 m-3">
  <div class="form-group">

  <div class="text-center mb-4">
    <p class="lead mb-3">
      {{ title }}
      <a href="{% url 'dashboard_profile' %}" type="butthon" class="close" aria-label="Close"> 
        <span aria-hidden="true">&times;</span>
      </a>
    </p>
  </div>

    {% csrf_token %}
    {% crispy form %}
    {{ contacts_formset.management_form | crispy }}
    <div>
    {% for form_ in contacts_formset %}
      <div class="individual-form">
      <div class="form-row">
        <div class="form-group col-md-6 mb-0">
          {{ form_.contact_type | as_crispy_field }}
        </div>
        <div class="form-group col-md-6 mb-0">
          {{ form_.contact_information | as_crispy_field }}
        </div>
      </div>
    </div>
    {% endfor %}

    <input type="submit" class="btn btn-lg btn-block btn-success can-blocked" value="Зарегистрировать компанию"></input>

  </div>
</form> 


    <script type="text/javascript">
    nodeForms = Array.from(document.getElementsByTagName('form'));
    for (form of nodeForms) {
      form.addEventListener('submit', function () {
       
        nodeItems = Array.from(document.getElementsByClassName('can-blocked'));
        for (c of nodeItems) {
          c.disabled=true;
        }
      });
    }
    </script>

{% endblock %}


Код теста
def test_add_valid_input(self):
        """ Тест запроса и ввод валидных данных """
        self.client.login(username=self.credentials['username'],
                          password=self.credentials['password'])
        response = self.client.get(reverse_lazy('companies_registration'))
        self.assertEqual(response.status_code, HTTPStatus.OK)
        response = self.client.post(reverse_lazy('companies_registration'),
             {'name': 'Some company',
             'description': 'Some description',
             'logo_url': ''})
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertRedirects(response, reverse('dashboard_company',
            kwargs={'pk': self.data_collection['company'].id}))


Так же заметил странность: часть кода не выполняется при отладке тестов. Однако это же участка кода выполняется при запуске сервера через manage.py и отрабатывает корректно. Я говорю про строкуи
profile = get_object_or_404(Profiles, user__id=self.request.user.id)
company = form.save(commit=False)
company.owner = profile
company.save()

6078646541eb7224462686.png
Собственно я хотел уточнить следующие моменты:
- как корректно писать тесты для форм с формсетами;
- как работает тестирование в Django, а именно - почему часть кода не выполняется в тесте?
  • Вопрос задан
  • 182 просмотра
Решения вопроса 1
Drakonn
@Drakonn Автор вопроса
Инженер-программист
Решил проблему путём добавления в передаваемые в POST запросе данных о формсете:
{'name': 'Some company',
            'description': 'Some description',
            'logo_url': '',
            'form-TOTAL_FORMS': '5',
            'form-INITIAL_FORMS': '0',
            'form-MAX_NUM_FORMS': '5',
            'form-MIN_NUM_FORMS': '0'})

Полный код теста

def test_add_valid_input(self):
        """ Тест запроса и ввод валидных данных """
        self.client.login(username=self.credentials['username'],
                          password=self.credentials['password'])
        response = self.client.get(reverse_lazy('companies_registration'))
        self.assertEqual(response.status_code, HTTPStatus.OK)

        response = self.client.post(reverse_lazy('companies_registration'),
            {'name': 'Some company',
            'description': 'Some description',
            'logo_url': '',
            'form-TOTAL_FORMS': '5',
            'form-INITIAL_FORMS': '0',
            'form-MAX_NUM_FORMS': '5',
            'form-MIN_NUM_FORMS': '0'})
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertRedirects(response, reverse('dashboard_company',
            kwargs={'pk': self.data_collection['company'].id}))


Однако такое решение не кажется мне корректным, подскажите как это сделать правильно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы