В моем текущем проекте мне трудно найти хорошее решение для создания масштабируемых интеграционных тестов, которые не имеют побочных эффектов. Небольшое уточнение о свободном от побочных эффектов свойстве: в основном это касается базы данных; после завершения тестов в базе данных не должно быть никаких изменений (состояние должно быть сохранено). Возможно, масштабируемость и сохранение состояния не объединяются, но я действительно хочу стремиться к лучшему решению.
Вот типичный интеграционный тест (эти тесты касаются уровня базы данных):
public class OrderTests {
List<Order> ordersToDelete = new ArrayList<Order>();
public testOrderCreation() {
Order order = new Order();
assertTrue(order.save());
orderToDelete.add(order);
}
public testOrderComparison() {
Order order = new Order();
Order order2 = new Order();
assertFalse(order.isEqual(order2);
orderToDelete.add(order);
orderToDelete.add(order2);
}
// More tests
public teardown() {
for(Order order : ordersToDelete)
order.delete();
}
}
Как можно себе представить, этот подход дает очень медленные тесты. А применительно ко всем интеграционным тестам требуется около 5 секунд, чтобы протестировать только небольшую часть системы. Я могу представить, что это число будет расти, когда охват увеличится.
Каков был бы другой подход для написания таких тестов? Одна альтернатива, о которой я могу подумать, - это иметь вид глобальных переменных (внутри класса), и все методы тестирования разделяют эту переменную. В результате только несколько заказов создаются и удаляются; в результате чего более быстрые тесты. Тем не менее, я думаю, что это представляет большую проблему; тесты больше не изолированы, и их становится все труднее понимать и анализировать.
Может случиться так, что интеграционные тесты не предназначены для запуска так часто, как модульные тесты; поэтому низкая производительность может быть приемлемой для тех. В любом случае было бы замечательно узнать, если кто-то придумал альтернативы для улучшения масштабируемости.
Это вечная проблема, с которой сталкиваются все при написании интеграционных тестов.
Идеальное решение, особенно если вы тестируете на производстве, - это открытие транзакции при настройке и откат ее до завершения. Я думаю, что это должно удовлетворить ваши потребности.
Там, где это невозможно, например, когда вы тестируете приложение на уровне клиента, другое решение состоит в том, чтобы использовать БД на виртуальной машине, сделать моментальный снимок при настройке и вернуться к нему в состоянии разрыва (это не так. займет столько времени, сколько вы можете ожидать).
источник
Интеграционные тесты всегда должны выполняться в соответствии с настройками производства. В вашем случае это означает, что вы должны иметь одну и ту же базу данных и сервер приложений. Конечно, ради производительности вы можете использовать БД в памяти.
Однако никогда не следует расширять объем транзакций. Некоторые люди предложили взять контроль над транзакцией и откатить ее после тестов. Когда вы сделаете это, все юридические лица (если вы используете JPA) будут оставаться прикреплены к контексту персистенции на протяжении выполнения теста. Это может привести к некоторым очень неприятным ошибкам, которые очень трудно найти .
Вместо этого вам следует очищать базу данных вручную после каждого теста с помощью библиотеки, такой как JPAUnit или аналогичной этому подходу (очистить все таблицы с использованием JDBC).
Что касается проблем с производительностью, вам не следует выполнять интеграционные тесты для каждой сборки. Пусть ваш сервер непрерывной интеграции сделает это. Если вы используете Maven, вам может понравиться подключаемый модуль отказоустойчивости, который позволяет разделить ваши тесты на модульные и интеграционные тесты.
Кроме того, вы не должны ничего издеваться. Помните, что вы проводите интеграционное тестирование, т.е. тестирование поведения в среде выполнения во время выполнения.
источник
По масштабируемости
Я уже сталкивался с этой проблемой несколько раз раньше, когда интеграционные тесты выполнялись слишком долго и не практично для одного разработчика постоянно работать в тесной обратной связи с изменениями. Некоторые стратегии, чтобы справиться с этим:
Попробуйте объединить эти методы для большего эффекта.
источник
В целях тестирования мы использовали развертывание базы данных SQLite на основе файлов (просто скопируйте ресурс). Это было сделано для того, чтобы мы могли также проверить миграцию схемы. Насколько мне известно, изменения схемы не являются транзакционными, поэтому не будут откатываться после отмены транзакции. Также отсутствие необходимости полагаться на поддержку транзакций для настройки теста позволяет правильно проверить поведение транзакций из вашего приложения.
источник