Результат всегда один и тот же: мы обнаруживаем проблемы позднее, чем могли бы, их исправление оказывается более сложным делом, а наши заказчики получают неудачный результат, что, в свою очередь, создает излишнюю нагрузку на весь поток создания ценности.
Для смягчения ситуации предпочтительно иметь небольшое число надежных автоматизированных тестов, а не много проводимых вручную или ненадежных автоматических. Поэтому мы ориентированы на автоматизацию только тех тестов, которые действительно подтверждают желанные для нас бизнес-цели. Если отказаться от тестирования дефектов, обнаруживающихся в производственной среде, то мы должны добавить их обратно в набор тестов, осуществляемых вручную, и в идеале обеспечить их автоматизацию.
Гэри Грувер, ранее работавший вице-президентом по качеству разработок, релиза ПО и эксплуатации компании Macys.com, так описывал свои впечатления: «На нашем сайте электронной коммерции крупного розничного продавца мы перешли от 1300 тестов, выполняемых вручную каждые десять дней, к десяти автоматизированным, запускаемым при каждой записи изменений кода. Гораздо лучше выполнить несколько надежных тестов, чем много ненадежных. С течением времени мы расширили этот набор до сотен тысяч автоматизированных тестов».
Другими словами, мы начинаем с небольшого числа надежных автоматических проверок и с течением времени увеличиваем их количество, все сильнее укрепляя уверенность, что мы быстро обнаружим любые изменения в системе, способные вывести ее из состояния готовности к развертыванию.
Встраиваем тесты производительности в программу тестирования
Слишком часто мы обнаруживаем во время интеграционного тестирования или уже после развертывания в производственную среду, что наше приложение имеет низкую производительность. Проблемы производительности зачастую трудно обнаружить, например, когда работа замедляется с течением времени, и они остаются незамеченными, пока не становится слишком поздно (к примеру, запросы к базе данных без использования индекса). И многие из этих проблем сложно решать, особенно когда они вызваны принятыми нами архитектурными решениями или непредвиденными ограничениями нашей сети, базы данных, системы хранения данных или других систем.
Наша цель — написать и запустить автоматические тесты производительности, проверяющие производительность всего стека приложения (код, базы данных, хранилища, сети, виртуализация и так далее) в рамках конвейера развертывания, чтобы мы могли обнаруживать проблемы на раннем этапе, когда внесение исправлений делается быстро и обходится малой ценой.
Поняв, как наше приложение и среды ведут себя под нагрузкой, близкой к реальной, мы можем гораздо лучше планировать мощности нашей системы, а также выявлять нижеперечисленные ситуации и подобные им:
• время выполнения запроса к базе данных растет нелинейно (например, мы забыли включить индексирование базы данных, и время загрузки страницы увеличивается с тридцати секунд до ста минут);
• изменение кода вызывает десятикратное увеличение количества вызовов базы данных, нагрузки на системы хранения или сетевого трафика.
Если у нас проводятся приемочные испытания и они могут выполняться параллельно, то мы используем их как основу для наших тестов производительности. Например, предположим, что мы работаем с сайтом электронной торговли и определили, что операции «поиск» и «оформить заказ» важны и должны хорошо выполняться даже под нагрузкой. Для проверки этого мы можем запустить одновременно тысячи приемочных тестов поиска и тысячи приемочных тестов оформления заказа.
Из-за большого объема вычислений и операций ввода-вывода, необходимых для выполнения тестов производительности, создание среды для такого тестирования может оказаться более сложным, чем создание производственной среды для самого приложения. Поэтому мы должны создавать среду для тестирования производительности в начале любого проекта и обеспечивать выделение всех ресурсов, необходимых, чтобы она функционировала корректно и на начальных этапах.
Чтобы в начале работы выявить проблемы с производительностью, мы должны регистрировать результаты тестов производительности и оценивать результаты каждого запуска по сравнению с предыдущими результатами. Например, мы можем посчитать, что тест не пройден, если производительность отличается более чем на 2 % от результатов предыдущего запуска.
Читать дальше