Задать вопрос
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, а именно - почему часть кода не выполняется в тесте?
  • Вопрос задан
  • 200 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 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}))


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

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

Похожие вопросы
Strikt Москва
от 100 000 до 180 000 ₽
ITK academy Саратов
от 75 000 ₽
Sim-Ba Pay Санкт-Петербург
от 180 000 ₽