K
K
Konstantin2021-04-15 19:21:45
Django
Konstantin, 2021-04-15 19:21:45

Django. form tests. How does the test work?

Hello. I'm writing an integration test of a form.
There is a form with an inline formset that works correctly, but tests for adding elements do not pass (post requests). Tests fail

Control form data is missing or corrupted
. There are no problems when accessing through the browser.
Source codes

Код формы
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}))


I also noticed strangeness : part of the code is not executed when debugging tests. However, the same piece of code is executed when the server is started via manage.py and works correctly. I'm talking about strings
profile = get_object_or_404(Profiles, user__id=self.request.user.id)
company = form.save(commit=False)
company.owner = profile
company.save()

6078646541eb7224462686.png
Actually, I wanted to clarify the following points:
- how to correctly write tests for forms with formsets;
- how does testing work in Django, namely - why is a piece of code not being executed in a test?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
Konstantin, 2021-04-15
@Drakonn

I solved the problem by adding the formset data to the POST request:

{'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'})

Full test code

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}))


However, this solution does not seem correct to me, tell me how to do it correctly.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question