Ответ 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 в этом отношении.
Это все, даже если вы рассматриваете сложности, возникающие при развертывании, имеющие части вашего проекта в разных репозиториях, зависящие друг от друга, создающие пакеты для установки и т.д.
В общем, я хотел бы услышать от кого-то, кто считает, что они нашли хорошее решение этой проблемы. Это далеко не тривиальный вопрос, как подразумевают некоторые комментаторы.