Что такое Apache JMeter?
Apache JMeter — это open-source приложение на Java, предназначенное для нагрузочного тестирования и измерения производительности веб-приложений. Изначально созданный для тестирования веб-приложений, JMeter расширился и теперь поддерживает множество протоколов, включая HTTP, HTTPS, SOAP, REST, FTP, JDBC, LDAP, JMS и SMTP.
JMeter — один из наиболее широко используемых инструментов тестирования производительности в индустрии. Его популярность объясняется бесплатностью, расширяемостью через плагины и большим сообществом. Если вы работаете в QA, вы почти наверняка столкнётесь с JMeter в какой-то момент карьеры.
Архитектура JMeter
JMeter использует древовидную структуру для организации планов тестирования. Понимание основных компонентов необходимо перед созданием первого теста.
Test Plan
Test Plan — это корневой элемент. Он содержит все элементы вашего теста. План тестирования определяет, что тестировать и как это делать. Его можно рассматривать как контейнер для всего сценария нагрузочного тестирования.
Thread Groups
Thread Group — это точка входа вашего теста. Он управляет:
- Number of Threads (пользователи): Сколько виртуальных пользователей будут выполнять тест одновременно
- Ramp-Up Period: Сколько времени JMeter тратит на запуск всех потоков. Ramp-up 60 секунд при 100 потоках означает, что JMeter запускает примерно 1,67 пользователя в секунду
- Loop Count: Сколько раз каждый поток выполняет план тестирования. Установите “Infinite” для тестов на основе длительности
- Duration: Максимальное время выполнения теста (полезно с бесконечными циклами)
Samplers
Samplers указывают JMeter отправлять запросы на сервер. Наиболее распространённый — HTTP Request Sampler, который отправляет HTTP/HTTPS запросы. Другие samplers включают JDBC Request (базы данных), FTP Request и SMTP Sampler (электронная почта).
Ключевые поля HTTP Request Sampler:
- Protocol: HTTP или HTTPS
- Server Name or IP: Целевой сервер
- Port Number: Обычно 80 (HTTP) или 443 (HTTPS)
- Method: GET, POST, PUT, DELETE и т.д.
- Path: Путь эндпоинта (например,
/api/users) - Body Data: Тело запроса для POST/PUT
Listeners
Listeners собирают и отображают результаты тестов. Наиболее распространённые:
| Listener | Назначение |
|---|---|
| View Results Tree | Детальный просмотр каждого запроса/ответа (только для отладки) |
| Summary Report | Таблица агрегированной статистики |
| Aggregate Report | Статистика с перцентилями |
| Graph Results | Визуальный график времён ответа |
| Simple Data Writer | Сохраняет результаты в файл для внешнего анализа |
Важно: View Results Tree потребляет значительный объём памяти. Отключайте его во время реальных нагрузочных тестов и используйте только для отладки с малым числом потоков.
Assertions
Assertions проверяют, что ответы соответствуют ожидаемым критериям. Если assertion не проходит, JMeter помечает sampler как неуспешный.
- Response Assertion: Проверяет тело ответа, заголовки или код состояния
- Duration Assertion: Не проходит, если время ответа превышает пороговое значение
- Size Assertion: Проверяет размер ответа
- JSON Assertion: Проверяет содержимое JSON-ответа
- XPath Assertion: Проверяет содержимое XML-ответа
Timers
Timers добавляют задержки между запросами для имитации реалистичного поведения пользователей. Без таймеров JMeter отправляет запросы максимально быстро, что нереалистично.
- Constant Timer: Фиксированная задержка между запросами
- Gaussian Random Timer: Случайная задержка с нормальным распределением
- Uniform Random Timer: Случайная задержка в заданном диапазоне
Config Elements
Config Elements настраивают значения по умолчанию и переменные для samplers:
- HTTP Cookie Manager: Автоматически управляет cookies (необходимо для приложений с сессиями)
- HTTP Header Manager: Добавляет заголовки ко всем запросам
- CSV Data Set Config: Читает тестовые данные из CSV-файлов для параметризации
- HTTP Request Defaults: Устанавливает значения по умолчанию, общие для нескольких HTTP samplers
Запись HTTP-запросов
JMeter включает Test Script Recorder (ранее HTTP Proxy Server), который захватывает трафик браузера и преобразует его в samplers JMeter. Это самый быстрый способ создать реалистичный сценарий тестирования.
Шаги для записи:
- Добавьте Thread Group в Test Plan
- Добавьте HTTP(S) Test Script Recorder под Test Plan
- Установите порт (по умолчанию: 8888)
- Настройте браузер на использование
localhost:8888в качестве прокси - Нажмите Start в записывающем устройстве
- Навигируйте по приложению в браузере
- Остановите запись — JMeter создаст samplers для каждого захваченного запроса
После записи очистите скрипт, удалив ненужные запросы (статические ресурсы, вызовы аналитики) и добавьте параметризацию для динамических значений.
Параметризация
Параметризация заменяет жёстко заданные значения переменными, чтобы каждый виртуальный пользователь мог использовать разные данные. Наиболее распространённый подход использует CSV Data Set Config.
Создайте CSV-файл (users.csv):
username,password
user1,pass123
user2,pass456
user3,pass789
Добавьте элемент CSV Data Set Config с параметрами:
- Filename: Путь к вашему CSV-файлу
- Variable Names:
username,password - Delimiter:
, - Recycle on EOF: True (начинает сначала, когда файл заканчивается)
- Sharing Mode: All threads (каждый поток читает следующую строку)
Ссылайтесь на переменные в samplers с помощью ${username} и ${password}.
Корреляция
Корреляция — это извлечение динамических значений из ответов сервера и использование их в последующих запросах. Это критически важно для приложений, использующих токены сессии, CSRF-токены или динамические идентификаторы.
Используйте Regular Expression Extractor или JSON Extractor как постпроцессор на sampler, который возвращает динамическое значение:
- Reference Name: Имя переменной (например,
sessionToken) - Regular Expression: Паттерн для поиска (например,
"token":"(.+?)") - Template:
$1$(первая группа захвата) - Match No.:
1(первое совпадение)
Затем используйте ${sessionToken} в последующих запросах.
Запуск JMeter из командной строки
Для реальных нагрузочных тестов всегда используйте режим командной строки (без GUI). GUI потребляет слишком много ресурсов и искажает результаты.
jmeter -n -t test_plan.jmx -l results.jtl -e -o report_folder
Флаги:
-n— Режим без GUI-t— Файл плана тестирования-l— Файл журнала результатов-e -o— Генерация HTML-отчёта после теста
Упражнение: Нагрузочное тестирование REST API с JMeter
Создайте план тестирования в JMeter, имитирующий 50 пользователей, просматривающих API книжного магазина в течение 5 минут.
Сценарий
Вы тестируете REST API онлайн-книжного магазина с такими эндпоинтами:
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/books | GET | Список всех книг |
/api/books/{id} | GET | Получить детали книги |
/api/auth/login | POST | Аутентификация пользователя |
/api/cart | POST | Добавить книгу в корзину |
Требования
- Создайте Thread Group с 50 пользователями, ramp-up 120 секунд, длительность 5 минут
- Добавьте HTTP Request Defaults с именем сервера
- Добавьте HTTP Cookie Manager для управления сессиями
- Создайте HTTP Samplers для каждого эндпоинта
- Параметризуйте учётные данные пользователей из CSV-файла
- Коррелируйте токен аутентификации из ответа на логин
- Добавьте Response Assertions для проверки кодов состояния
- Добавьте Constant Timer (1-3 секунды) между запросами
- Добавьте listeners Summary Report и Aggregate Report
- Запустите в режиме без GUI и сгенерируйте HTML-отчёт
Подсказка: Структура Test Plan
Дерево вашего плана тестирования должно выглядеть так:
Test Plan
├── HTTP Request Defaults (server: api.bookstore.example.com)
├── HTTP Cookie Manager
├── CSV Data Set Config (users.csv)
├── Thread Group (50 пользователей, 120с ramp-up, длительность: 300с)
│ ├── HTTP Request: Логин (POST /api/auth/login)
│ │ ├── JSON Extractor (token из ответа)
│ │ └── Response Assertion (status = 200)
│ ├── HTTP Header Manager (Authorization: Bearer ${token})
│ ├── Constant Timer (2000мс)
│ ├── HTTP Request: Список книг (GET /api/books)
│ │ └── JSON Extractor (bookId из ответа)
│ ├── Constant Timer (2000мс)
│ ├── HTTP Request: Детали книги (GET /api/books/${bookId})
│ │ └── Response Assertion (status = 200)
│ ├── Constant Timer (1000мс)
│ ├── HTTP Request: Добавить в корзину (POST /api/cart)
│ │ └── Response Assertion (status = 201)
│ ├── Summary Report
│ └── Aggregate Report
Решение: Ключевые детали конфигурации
CSV Data Set Config:
Filename: users.csv
Variable Names: username,password
Delimiter: ,
Recycle on EOF: True
Тело запроса логина:
{
"username": "${username}",
"password": "${password}"
}
JSON Extractor на ответе логина:
Reference Name: token
JSON Path: $.token
Match No.: 1
Default Value: TOKEN_NOT_FOUND
HTTP Header Manager:
Authorization: Bearer ${token}
JSON Extractor на списке книг:
Reference Name: bookId
JSON Path: $.books[0].id
Match No.: 0 (случайное совпадение)
Анализ результатов — На что обращать внимание:
- Среднее время ответа: Должно быть ниже вашего SLA (например, < 500мс)
- Процент ошибок: Должен быть 0% при нормальной нагрузке
- Пропускная способность (Throughput): Запросы в секунду, которые сервер может обработать
- 90-й перцентиль: 90% запросов выполняются за это время
- Если ошибки растут во время ramp-up: Сервер может испытывать трудности с конкурентными подключениями
- Если время ответа растёт линейно с числом пользователей: Сервер достигает предела мощности
Команда для запуска:
jmeter -n -t bookstore_test.jmx -l results.jtl -e -o ./report
Откройте report/index.html для просмотра интерактивного HTML-дашборда с графиками времён ответа, пропускной способности и уровня ошибок во времени.
Профессиональные советы
- Распределённое тестирование: Для масштабных тестов используйте распределённый режим JMeter с несколькими подчинёнными машинами. Один контроллер отправляет план тестирования на несколько генераторов нагрузки.
- JMeter Plugins Manager: Установите Plugins Manager (
jmeter-plugins.org) для дополнительных listeners, таких как график Transactions per Second и Ultimate Thread Group для сложных профилей нагрузки. - BeanShell vs JSR223: Всегда используйте JSR223 + Groovy для скриптинга вместо BeanShell. Groovy компилируется в байткод и значительно быстрее под нагрузкой.
- Think Time: Реальные пользователи делают паузы между действиями. Добавляйте таймеры со случайными задержками (Gaussian Random Timer с отклонением 2000мс и смещением 1000мс) для реалистичной симуляции.
- Assertions при нагрузке: Отключайте View Results Tree во время нагрузочных тестов. Используйте только Summary Report или записывайте результаты в JTL-файл для последующего анализа.