Модульное тестирование Django для редактирования формы

Возможно, кто-то уже разработал технику для облегчения скуки для следующего идиоматического unit test:

  • ПОЛУЧИТЬ URL-адрес с уже заполненными данными формы
  • POST переработанная форма с одним или несколькими полями, отредактированными
  • Проверить ответ (прибыль!)

Шаг 2 - самый утомительный цикл, проходящий через поля формы. Есть ли временные хаки для тестирования форм Django?

[Обновление: я не тестирую обработку форм Django. Я проверяю, что мое приложение производит правильные ответы, когда пользователь вносит изменения в форму. Это приложение, которое обрабатывает клиническую информацию, отсюда и множество возможных ответов на тест.]

8 ответов

Это зависит от того, что вы пытаетесь проверить. Я бы нацелил ваши тесты немного более тонко, чем кажется, что вы делаете.

Если код, который вам нужно проверить, является логикой проверки формы, я просто просто создаю экземпляр класса формы непосредственно в ваших тестах, передаю ему различные словари данных и вызову .is_valid(), проверьте правильность ошибок или их отсутствие. Не нужно включать HTML или HTTP-запросы.

Если он рассматривает логику (которую ИМО следует свести к минимуму), которую вы тестируете, вы, вероятно, захотите использовать тестовый клиент, но вам не нужно делать многоэтапные тесты или очень много тестов на этом уровне. При тестировании логики просмотра я бы не очистил HTML (это тестовые шаблоны), я бы использовал response.context, чтобы вытащить объект формы из контекста.

Если то, что вы хотите протестировать, состоит в том, что шаблоны содержат надлежащий HTML-код, чтобы заставить форму работать на самом деле (чтобы уловить ошибки, например забыть о включении формы управления для набора форм в шаблон), я использую WebTest и django-webtest, которые анализируют ваш HTML и упрощают для заполнения значений полей и отправки формы, как в браузере.


Вы можете использовать response.context и form.initial, чтобы получить значения, которые вам нужно отправить:

update_url = reverse('myobject_update',args=(myobject.pk,))
# GET the form
r = self.client.get(update_url)
# retrieve form data as dict
form = r.context['form']
data = form.initial # form is unbound but contains data
# manipulate some data
data['field_to_be_changed'] = 'updated_value'
# POST to the form
r = self.client.post(update_url, data)
# retrieve again
r = self.client.get(update_url)
self.assertContains(r, 'updated_value') # or
self.assertEqual(r.context['form'].initial['field_to_be_changed'], 'updated_value')


django-webtest идеально подходит для таких тестов:

from django_webtest import WebTest
class MyTestCase(WebTest):
 def test_my_view(self)
 form = self.app.get('/my-url/').form
 self.assertEqual(form['my_field_10'].value, 'initial value')
 form['field_25'] = 'foo'
 response = form.submit() # all form fields are submitted

По-моему, это лучше, чем саржа для тестирования django, потому что он обеспечивает доступ к внутренним django, поэтому поддерживаются встроенные django response.context, response.templates, self.assertTemplateUsed и self.assertFormError API.

С другой стороны, это лучше, чем собственный клиент теста django, поскольку он имеет гораздо более мощный и простой API.

Я немного предвзятый;), но я считаю, что django-webtest теперь лучший способ написать тесты django.


Это неясно, но можно догадаться, что у вас есть такие тесты.

class TestSomething( TestCase ):
 fixtures = [ "..." ]
 def test_field1_should_work( self ):
 response= self.client.get( "url with form data already populated" )
 form_data = func_to_get_field( response )
 form_data['field1']= new value
 response= self.client.post( "url", form_data )
 self.assert()
 def test_field2_should_work( self ):
 response= self.client.get( "url with form data already populated" )
 form_data = func_to_get_field( response )
 form_data['fields']= new value
 response= self.client.post( "url", form_data )
 self.assert()

Во-первых, вы слишком много делаете. Упростить.

class TestFormDefaults( TestCase ):
 fixtures = [ "some", "known", "database" ]
 def test_get_should_provide_defaults( self ):
 response= self.client.get( "url with form data already populated" )
 self.assert(...)

Вышеприведенный пример показывает, что значения по умолчанию заполняют формы.

class TestPost( TestCase ):
 fixtures = [ "some", "known", "database" ]
 def test_field1_should_work( self ):
 # No need to GET URL, TestFormDefaults proved that it workd.
 form_data= { expected form content based on fixture and previous test }
 form_data['field1']= new value
 response= self.client.post( "url", form_data )
 self.assert()

Не тратьте время на то, чтобы "получить" каждый "пост". Вы можете доказать - отдельно - что операции GET работают. Если у вас есть это доказательство, просто выполните POST.

Если вы используете POSTS с высокой степенью специфичности для сеанса и состояниями, вы все равно можете выполнить GET, но не беспокойтесь, анализируя ответ. Вы можете доказать (отдельно), что он имеет точно правильные поля.

Чтобы оптимизировать отдых, рассмотрите это.

class TestPost( TestCase ):
 fixtures = [ "some", "known", "database" ]
 def test_many_changes_should_work( self ):
 changes = [
 ( 'field1', 'someValue', 'some expected response' ),
 ( 'field2', 'someValue' ),
 ...
 ]
 for field, value, expected in changes:
 self.client.get( "url" ) # doesn't matter what it responds, we've already proven that it works.
 form_data= { expected form content based on fixture and previous test }
 form_data[field]= value
 response self.client.post( "url", form_data )
 self.assertEquas( expected, who knows what )

Вышеупомянутое, очевидно, будет работать, но количество тестов кажется небольшим.


Подумайте о том, зачем вам нужно тестировать это. Формы являются частью основной функциональности Django и, как таковые, очень хорошо покрываются собственными модульными тестами Django. Если все, что вы делаете, это базовое создание/обновление, которое, по вашему мнению, похоже на случай, я не вижу причин писать для этого единичные тесты.


Я не вижу, как и почему вам нужны модульные тесты для этого. Мне кажется, что вы тестируете (и исправляете) возможный ввод пользователя, который очень просто покрывается проверкой формы Django (и проверкой модели в 1.2).


Возможно, вы ищете инструменты, которые выполняют тестирование переднего конца, например twill или selenium

Оба из них генерируют код python, который может быть включен в тесты django, поэтому, когда вы запускаете тесты, он открывает URL-адреса, публикует данные и проверяет все, что вы хотите!

Это должно помочь вам увидеть эти тесты, написанные для selenium, для приложения django с открытым исходным кодом.


Я бы посоветовал вам взглянуть на инструменты уровня приемочного тестирования, такие как платформа тестирования роботов или letucce, которые, как думают, просто хотят, чтобы вы делали "Я проверяю, что мое приложение производит правильные ответы, когда пользователь вносит изменения в форма", что больше похоже на тестирование приемника (black-box), чем на модульное тестирование.

Для instace робот позволяет вам определять свои тесты в табличной форме, вы определяете рабочий процесс один раз, а затем можете легко определить множество тестов, которые выполняют рабочий процесс с разными данными.

licensed under cc by-sa 3.0 with attribution.