После просмотра великолепного выступления Карла Мейера « Тестирование и Django » я использовал библиотеку Яна Бикинга WebTest для функциональных тестов через django-webtest . Я был очень впечатлен и хотел бы подчеркнуть один из моментов Карла — то, что использование WebTest для функциональных тестов лучше, чем использование клиента Django.
Зачем?
Несколько причин — вот несколько:
- WebTest позволяет вам моделировать взаимодействие с пользователем гораздо более точно, так как он хорош для разметки. Вместо ручного создания запросов GET и POST вы можете использовать API WebTest для перехода по ссылкам и отправки форм — это то, что на самом деле делают пользователи. В результате ваши тесты точно фиксируют пользовательские истории.
- В заключение следует сказать, что написание функциональных тестов с помощью WebTest проще и быстрее, чем использование тестового клиента Django. Гораздо проще заполнять формы, которые создают сложные массивы данных POST — это особенно заметно в наборах форм.
- Объект ответа WebTest поддерживает несколько способов анализа HTML-ответа , что упрощает создание сложных утверждений об ответе.
Смотрите с 29:48 в разговоре Карла для более подробной информации.
Пример функционального теста
Рассмотрим эту историю из функциональной спецификации:
Сотрудник может загрузить CSV для создания новых кредитных ассигнований для клиентов.
Вот WebTest для этого:
from django_webtest import WebTest
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django_dynamic_fixture import G
from myproject.credits import api
class TestAnAdmin(WebTest):
def setUp(self):
self.staff = G(User, is_staff=True)
self.customer = G(User, username='10000', is_staff=False)
def test_can_upload_a_csv_to_create_allocations(self):
index = self.app.get(reverse('credits-index'), user=staff)
# Specify the file content to upload and submit the form
form = index.forms['upload_form']
# CSV content should be: username, credits, start_date, end_date
content = "10000,250,2012-01-01,2013-01-01"
form['file'] = 'credits.csv', content
form.submit()
# Check that an allocation has been created
self.assertEqual(250, api.balance(customer))
self.assertEqual(1, api.allocations(customer).count())
Как видите, использование WebTest позволяет запечатлеть историю в простом и удобочитаемом тесте. Это основано на реальном функциональном тесте моего текущего проекта. Написание вышеуказанного теста заняло около 2 минут.
Другие полезные библиотеки тестирования
Тестовый пример использует django_dynamic_fixture для создания пользователей, указывая только атрибуты, относящиеся к тесту.
Обратите также внимание на то, что в примере TestCase и метода используется несколько необычное соглашение об именах, потому что я использую django_nose с плагином spec из библиотеки pinocchio . Это приводит к тому, что выходные данные читаются как истории из вашей функциональной спецификации:
$ ./manage.py test tests/functional/eshop/credits_tests.py
nosetests --verbosity 1 tests/functional/eshop/credits_tests.py --with-spec -x -s
An admin
- can upload a csv to create allocations
----------------------------------------------------------------------
Ran 1 tests in 0.269s
Это полезный способ запуска функциональных тестов. Это также подталкивает вас к разделению ваших наборов тестов на более тщательно названные, строго сфокусированные тестовые наборы — вместо того, чтобы объединять разрозненные тесты в один тестовый набор.
Резюме
Используйте WebTest для своих функциональных тестов — вы не пожалеете об этом.