Настройка надлежащего тестирования Django для TDD


Я игнорировал необходимость тестирования моего проекта на долгое время.

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

Я нашел много "обучающих программ" с шагами: "1. Установите это 2. Установите это 3. Установите это, а затем 4. Готово!",
но никто, кажется, не говорит о том, как структурировать ваши тесты, как файл, так и код.

И никто никогда не говорит о том, как настроить сервер CI, или просто интегрировать тестирование с развертыванием вашего проекта.
Многие люди говорят о ткани, виртуализации и носу, но никто не описывает, как они работают вместе с ними в целом.

То, что я продолжаю находить, - это подробная информация о том, как вы настраиваете правильную среду Rails при тестировании и CI и т.д.

Кто-нибудь еще чувствует, что сообщество Django не хватает в этой области, или это только я?:)

О, и есть ли у кого-нибудь еще какие-либо предложения о том, как это сделать?

Ответы

Ответ 1

Как я вижу, в этой проблеме есть несколько частей.

Одна вещь, которая вам нужна, это хорошие модульные тесты. Основная характеристика модульных тестов заключается в том, что они очень быстрые, так что они могут тестировать комбинаторные возможности ввода функций и охвата веток. Чтобы получить скорость и поддерживать изолированность между тестами, даже если они работают параллельно, модульные тесты не должны касаться базы данных, сети или файловой системы. Такие тесты трудно писать в проектах Django, потому что Django ORM позволяет удобно разбросать вызовы доступа к базе данных в вашем коде продукта. Следовательно, любые тесты кода Django неизбежно попадут в базу данных. В идеале вы должны подходить к этому, ограничивая доступ к базе данных в своем коде продукта тонким уровнем доступа к данным, созданным на основе ORM django, который предоставляет методы, соответствующие вашему приложению. Другой подход заключается в том, что ваши тесты будут издеваться над вызовами ORM. В худшем случае вы откажетесь от этого: ваши модульные тесты становятся интеграционными тестами: они фактически попадают в базу данных, пересекают несколько уровней вашей архитектуры и занимают несколько минут, что позволяет разработчикам часто запускать их достаточно часто.

Следствием этого является то, что писать тесты интеграции легко - канонический стиль тестов Django прекрасно охватывает это.

Последняя и самая сложная часть проблемы запускает ваши приемочные тесты. Определяющей характеристикой приемочных тестов является то, что они вызывают ваше приложение в конце, как пользователь делает на производстве, чтобы доказать, что ваше приложение действительно работает. Канонические тесты dhango с использованием django testrunner не соответствуют этому. Они не выдают фактически HTTP-запросы (вместо этого они анализируют конфигурацию url, чтобы выяснить, какое промежуточное ПО и представление будут вызваны для обработки конкретного запроса, а затем они вызовут его в процессе.) Это означает, что такие тесты не тестируют ваши webserver config, ни javascript, ни рендеринг в браузере и т.д. Чтобы проверить это, вам нужно что-то вроде селена.

Кроме того, у нас есть много серверных процессов, таких как задания cron, которые используют код из нашего проекта Django. Приемочные тесты, связанные с этими процессами, должны ссылаться на задания, как и на cron, в качестве нового процесса.

Оба этих сценария имеют некоторые проблемы. Во-первых, вы не можете просто запускать такие тесты под тестовым бегуном Django. Если вы попытаетесь это сделать, то вы обнаружите, что тестовые данные, которые вы написали во время тестовой установки (либо с помощью механизма django fixtures, либо путем простого вызова "MyModel(). Save()" в тесте) находятся в транзакция, которую ваш код продукта, работающий в другом процессе, не является стороной. Поэтому ваши тесты должны зафиксировать изменения, которые они делают, прежде чем код продукта сможет их увидеть. Это мешает очистке между тестами, которые Django testrunner помогает, поэтому вам нужно переключить его в другой режим, который явно удаляет, а не откатывается назад. К сожалению, это намного медленнее. В прошлую ночь группа пользователей Django в Лондоне, несколько разработчиков ядра Django, заверили меня, что у этого сценария также есть другие сложности (которые, как я признаю, я не знаю, что это такое), чего лучше избегать, не выполняя приемочные тесты в рамках Django, но создавая их как полностью автономный набор тестов.

Если вы это сделаете, то ваша непосредственная проблема в том, что вы потеряли преимущества, которые предоставляет тестовый runnner для Django: именно он создает тестовую базу данных и очищает ее между каждым тестом. Вам придется создать для вас какой-то эквивалентный механизм. Вам понадобится код продукта для работы с тестовой базой данных, если он вызывается как часть теста. Вы должны быть абсолютно уверены, что если код продукта запускается как часть теста, даже в производственной коробке, он НИКОГДА не может случайно коснуться производственной базы данных, поэтому этот механизм должен быть абсолютно безотказным. Например, забыть установить переменную среды в тестовой установке не должно вызывать blooper в этом отношении.

Это все, даже если вы рассматриваете сложности, возникающие при развертывании, имеющие части вашего проекта в разных репозиториях, зависящие друг от друга, создающие пакеты для установки и т.д.

В общем, я хотел бы услышать от кого-то, кто считает, что они нашли хорошее решение этой проблемы. Это далеко не тривиальный вопрос, как подразумевают некоторые комментаторы.

Ответ 3

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

У меня был лучший опыт тестирования с использованием полуфункционального инструмента тестирования testbrowser, который имитирует действия браузера в Python. Для интеграции с Django установите приложение homophony (отказ от ответственности: я являюсь автором приложения).

Testbrowser может быть слишком грубым для разработки, основанной на тестах, но это лучший инструмент тестирования тех, которые я использовал до сих пор. Самое главное, он масштабируется довольно хорошо, тогда как модульные тесты и инструменты для тестирования на основе браузера имеют тенденцию становиться очень хрупкими, поскольку ваше приложение растет в размерах.

Что касается инструмента CI, перейдите к Buildbot или Jenkins.

Ответ 4

Я использую сочетание Django отличное расширение рамочной системы python unittest для тестирования api/models/вспомогательных функций и селена для проверки браузера, Selenium имеет отличные инструкции по настройке и написанию тестов на python.