В мире разработки программного обеспечения тестирование является жизненно необходимым элементом. Существует несколько видов тестов: мы можем тестировать, функционал, безопасность и многое другое. При этом, одним из наиболее важных тестов является проверка работы приложения под нагрузкой. В продуктивной среде мы можем столкнуться с ситуацией, когда слишком большая нагрузка на приложение может привести к его выходу из строя.
Нагрузочное тестирование — это специфическое семейство тестов производительности, которое включает в себя множество одновременных пользовательских подключений, выполняющих одну и ту же программу действий в одно и то же время. Это делается для того, чтобы проверить, сможет ли инфраструктура системы справиться с нагрузкой без ущерба для функциональности или просто с приемлемым снижением производительности.
Нагрузочное тестирование используется для того, чтобы определить время отклика на критические действия в вашем приложении. Необходимо понимать, является ли данное значение приемлемым по сравнению со спецификацией, требованиями пользователей или KPI.
Также с помощью нагрузочных тестов нам необходимо выяснить правильно ли ведут себя ключевые бизнес‑функции при высокой нагрузке и рассчитана ли наша инфраструктура на масштабирование при стресс‑тестах.
Тестирование производительности фронтенда измеряет, насколько быстро ваш сайт загружается и отображает контент для пользователей. В отличие от этого, тестирование производительности внутреннего интерфейса включает в себя отправку нескольких запросов на ваш бэкенд, чтобы проверить, могут ли они обрабатывать одновременные запросы.
Именно поэтому нагрузочное тестирование так важно. И хотя существует множество коммерческих инструментов, которые могут помочь вам в этом процессе, в рамках данной статьи мы рассмотрим три решения с открытым кодом.
Но сначала мы рассмотрим основные моменты, связанные с нагрузочным тестированием.
Функциональное или нагрузочное
Нагрузочное тестирование обычно считается нефункциональным видом тестирования, поскольку оно направлено на проверку производительности, надежности и различных характеристик использования ресурсов, а не конкретных функций или пользовательского функционала.
Однако низкая производительность напрямую влияет на функционал, доступный пользователям и может сделать приложение фактически непригодным для использования, поэтому организациям не следует рассматривать проверки производительности как чисто нефункциональные. Нагрузочное тестирование пересекается с функциональным, особенно для выявления таких проблем, как условия гонки или утечки ресурсов, которые проявляются только под нагрузкой.
Наилучшим подходом является включение нагрузочного тестирования наряду с функциональным тестированием в общую программу тестирования для создания качественного продукта в целом. Специальное нагрузочное тестирование все равно необходимо, чтобы подвергнуть систему нагрузке и выявить пределы ее производительности.
Чем раньше, тем лучше
Довольно распространенной является практика проведения нагрузочных тестов на завершающих этапах процесса разработки. В результате мы можем столкнуться с ситуацией, когда у приложения есть явные проблемы с производительностью, но сложно выявить, какие компоненты наиболее подвержены деградации при увеличении нагрузки, так как мы тестируем приложение в целом.
Поэтому важно добавлять нагрузочное тестирование в практику проверок программного обеспечения на ранних этапах и на регулярной основе. Для этого есть несколько причин:
Во‑первых, нагрузочное тестирование позволяет разработчикам программного обеспечения оценить, как функционирует система в условиях повышенной нагрузки, например, когда к приложению одновременно обращаются несколько пользователей.
Во‑вторых, проведение нагрузочного тестирования на ранних этапах процесса разработки позволяет выявить потенциальные узкие места в производительности и проблемы масштабируемости и решить их заблаговременно, до того как они повлияют на конечных пользователей. Такой упреждающий подход не только помогает создать надежный и эффективный программный продукт, но и улучшает общее впечатление пользователей.
Кроме того, нагрузочное тестирование полезно даже для небольших приложений, поскольку оно дает ценную информацию о возможностях и ограничениях их производительности в стрессовых ситуациях. Регулярное нагрузочное тестирование помогает поддерживать и улучшать производительность программного обеспечения, обеспечивая его эффективную работу в реальных сценариях использования.
На этом рассмотрение теории нагрузочного тестирования можно завершить и далее мы перейдем к практическим решениям.
JMeter
Apache JMeter является наиболее распространенным решением с открытым кодом, разработанным специально для нагрузочного тестирования с возможностью измерения производительности приложений и времени отклика.
Ключевыми функциями JMeter являются возможности тестирования производительности различных технологий с использованием таких протоколов, как Web HTTP/HTTPS, SOAP и Rest Services, FTP и БД с помощью JDBC. При этом имеется хорошая IDE, которую можно использовать для записи, создания и отладки тестов производительности.

Начиная с JMeter 3.1, Groovy является языком программирования по умолчанию и с его помощью можно реализовывать логику нагрузочного тестирования. Также данное решение можно настроить для тестирования производительности мобильных приложений.
Помимо достоинств, у данного решения также есть и некоторые недостатки. Например, JMeter будет трудно масштабировать для больших распределенных тестов, особенно если вам нужно настроить множество машин, так как вы должны настроить их на взаимодействие друг с другом. Также могут возникнуть сложности с оркестровкой при выполнении больших тестов JMeter.
Документацию по установке и настройке данного решения можно найти на странице проекта.
Taurus
Технически Taurus не является инструментом нагрузочного тестирования, он действует скорее как обертка поверх других решений, которые скрывают сложность выполнения нагрузочных тестов.
Пожалуй, основным преимуществом Taurus является то, что он позволяет писать тесты на языке разметки YAML. Вы можете описать полноценный скрипт даже в десяти строках текста, что позволяет командам тестировщиков описывать свои тесты в файлах YAML или JSON.
В YAML файлах мы задаем один или несколько запросов. Для каждого сценария определяется исполнение с такими параметрами, как количество пользователей, продолжительность, период нарастания и так далее. Модули позволяют нам настроить исполнителя, который может быть Apache JMeter, Selenium и так далее. Аналогично, отчетность позволяет настроить, как должен быть сгенерирован отчет, т. е. csv, живой отчет в консоли или отправка результата на сайт blazemeter.

Благодаря возможности использовать YAML мы можем эффективно использовать Taurus в конвейере CI/CD. Говоря об интеграции с другими решениями, Taurus предоставляет слой абстракции поверх JMeter и некоторых других инструментов, таких как Locust, Gatling, Grinder и Selenium.
Locust
Еще один распространенный инструмент — Locust. Это достаточно простое в использовании, средство для нагрузочного тестирования приложений, которое поможет вам определить время отклика. Locust предназначен для написания сценариев тестирования производительности веб‑сайтов и других приложений.
Посмотрим пример простого теста на Python.
from locust import HttpUser, task
class HelloWorldUser(HttpUser):
@task
def hello_world(self):
self.client.get("/hello")
self.client.get("/world")
Здесь наш сценарий сначала выполнит HTTP‑запрос к /hello, затем к /world. Запустить тест можно из консоли, что очень удобно использовать в конвейере CI/CD.
Но, также с Locust можно работать через веб‑интерфейс. Например, мы можем указать количество пользовательских сессий, подключенных к нашему веб ресурсу, а также скорость, с которой должны создаваться новые сессии. В примере ниже у нас каждую секунду будут добавляться пять новых сессий, пока общее количество не достигнет сотни.

Статистику по ошибкам мы также можем получать в веб интерфейсе:

Таким образом, ключевыми особенностями Locust являются возможности создания тестовых сценариев с помощью Python, наличие функционала для работы как через командную строку, так и через веб интерфейс, возможность легко масштабировать количество пользователей, которых нужно эмулировать. Также Locust хорошо подходит для тестирования API.
Но, поскольку это более новый инструмент, у него гораздо меньше плагинов, чем у того же JMeter.
Заключение
Мы рассмотрели три инструмента для нагрузочного тестирования, и если Taurus является по сути надстройкой над другими решениями, то JMeter и Locust это самостоятельные решения. При выборе между ними важными критериями является наличие плагинов для проведения нужных тестов.
Но кроме того, стоит отметить, что такие инструменты, как JMeter, основаны на потоковой архитектуре, которая потребляет много ресурсов. С другой стороны, Locust использует подход, основанный на событиях, который потребляет меньший объем ресурсов. По некоторым оценкам, Locust потребляет примерно на 70% меньше ресурсов, чем JMeter.
Соответственно, при выборе конкретного решения вы можете отталкивать от тех характеристик и возможностей, которые имеются у того или иного решения и которое может взаимодействовать с вашим приложением.
Для тех, кто хочет не только освоить теорию, но и практическими шагами улучшить производительность своих систем, предлагаем несколько вебинаров по нагрузочному тестированию и работе с актуальными инструментами. Если вы хотите расширить свои знания или быстро приступить к решению реальных задач — эти уроки помогут вам сэкономить время и сразу перейти к делу:
29 апреля — Gatling и K6: тесты для gRPC, WebSocket и HTTP
Освойте работу с различными протоколами и сравните два популярных инструмента для тестирования под нагрузкой — K6 и Gatling.13 мая — Минимум для старта: как провести свое первое нагрузочное тестирование
Простой и эффективный план для тех, кто хочет быстро запустить нагрузочное тестирование и извлечь из этого максимум пользы.