Что такое Apache JMeter?

Apache JMeter — это open-source приложение на Java, предназначенное для нагрузочного тестирования и измерения производительности веб-приложений. Изначально созданный для тестирования веб-приложений, JMeter расширился и теперь поддерживает множество протоколов, включая HTTP, HTTPS, SOAP, REST, FTP, JDBC, LDAP, JMS и SMTP.

JMeter — один из наиболее широко используемых инструментов тестирования производительности в индустрии. Его популярность объясняется бесплатностью, расширяемостью через плагины и большим сообществом. Если вы работаете в QA, вы почти наверняка столкнётесь с JMeter в какой-то момент карьеры.

Архитектура JMeter

JMeter использует древовидную структуру для организации планов тестирования. Понимание основных компонентов необходимо перед созданием первого теста.

graph TD TP[Test Plan] --> TG1[Thread Group 1] TP --> TG2[Thread Group 2] TG1 --> S1[HTTP Sampler: Логин] TG1 --> S2[HTTP Sampler: Просмотр товаров] TG1 --> S3[HTTP Sampler: Добавление в корзину] S1 --> A1[Response Assertion] S1 --> PP1[Regular Expression Extractor] TG1 --> T1[Constant Timer] TG1 --> L1[View Results Tree] TG1 --> L2[Summary Report] TG1 --> CE1[HTTP Cookie Manager] TG1 --> CE2[CSV Data Set Config]

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. Это самый быстрый способ создать реалистичный сценарий тестирования.

Шаги для записи:

  1. Добавьте Thread Group в Test Plan
  2. Добавьте HTTP(S) Test Script Recorder под Test Plan
  3. Установите порт (по умолчанию: 8888)
  4. Настройте браузер на использование localhost:8888 в качестве прокси
  5. Нажмите Start в записывающем устройстве
  6. Навигируйте по приложению в браузере
  7. Остановите запись — 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/booksGETСписок всех книг
/api/books/{id}GETПолучить детали книги
/api/auth/loginPOSTАутентификация пользователя
/api/cartPOSTДобавить книгу в корзину

Требования

  1. Создайте Thread Group с 50 пользователями, ramp-up 120 секунд, длительность 5 минут
  2. Добавьте HTTP Request Defaults с именем сервера
  3. Добавьте HTTP Cookie Manager для управления сессиями
  4. Создайте HTTP Samplers для каждого эндпоинта
  5. Параметризуйте учётные данные пользователей из CSV-файла
  6. Коррелируйте токен аутентификации из ответа на логин
  7. Добавьте Response Assertions для проверки кодов состояния
  8. Добавьте Constant Timer (1-3 секунды) между запросами
  9. Добавьте listeners Summary Report и Aggregate Report
  10. Запустите в режиме без 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-файл для последующего анализа.