Gatling — большой гайд

Плюсы Gatling

Неформальным стандартом тестирования производительности сейчас является JMeter. Gatling проще. Кроме того, он тоже бесплатный, и базовая версия покрывает почти всё нужное. Неплохая документация и поддержка, регулярно проводятся вебинары. Gatling написан на Scala, что позволяет запускать его на любой ОС. Достаточно мощный благодаря удачной асинхронной архитектуре, многие считают, что Gatling работает с нагрузкой чуть лучше чем JMeter, экономнее использует процессор и память. Есть assertions, GUI, детальные метрики и продуманные отчеты. Интегрируется с Grafana и Taurus.

Установка и настройка

Версия Java

Gatling поддерживает 64-битный OpenJDK LTS, версии: 11, 17, 21. Другие JVM, такие как: 32-битные системы или OpenJ9 — не поддерживаются.

Языки

Начиная с версии 3.7, Gatling позволяет писать тесты на языках Java, Kotlin и Scala (до версии 3.7 — только на Scala).

Версия Gatling

Перед тем как приступать, проверьте здесь, что используется последняя версия.

Standalone-пакет

Можно использовать standalone-пакет Gatling; тогда понадобится только текстовый редактор (возможно, с синтаксической подсветкой Java, или Scala), и можно будет запускать Gatling из командной строки. Скачать пакет — здесь. Пакет поддерживает только Java и Scala (Kotlin не поддерживает). Для Kotlin потребуется проект maven или gradle.

Распакуйте скачанный пакет в нужную папку. Для запуска Gatling и Recorder используйте скрипты, расположенные в каталоге bin.

Пользователям Windows: не советуем ставить Gatling в папке Programs, так как могут быть проблемы с правами на запись.

Для запуска Gatling надо сначала установить JDK, как минимум JDK11.

Подробности по установке и настройке операционной системы (ОС) приведены в разделе Operations на оф.сайте Gatling.

Скрипты запуска Gatling и плагин Gatling maven зависят от переменной JAVA_HOME. В зависимости от настроек, может быть, что у вас стоит версия, отличная от той, которая выводится командой java -version. Если вы видите непонятные ошибки типа Unsupported major.minor version, и у вас JDK11 или более новая, то возможно нужно явно задать переменную JAVA_HOME.

Структура standalone-пакета выглядит так:

  • bin: скрипты запуска Gatling и Recorder.
  • conf: конфигурационные файлы Gatling, Akka и Logback.
  • lib: бинарные файлы Gatling и зависимостей
  • user-files:
    • simulations: здесь будет код ваших нагрузочных симуляций (Simulations). Необходимо соблюдать иерархию папок!
    • resources: ресурсы, не относящиеся к исходному коду, например файлы фидеров и шаблоны тел запросов.
    • lib: здесь можно добавлять собственные зависимости (JAR-файлы). При работе в Gatling Enterprise-версии они упаковываются в один «толстый» JAR-файл вместе с нагрузочными симуляциями.
  • results: сюда генерируются результаты тестирования.

Инструменты сборки

Maven

Maven можно использовать для сборки проектов на Java, Kotlin и Scala.

Gatling предоставляет официальный плагин для maven gatling-maven-plugin. Он позволяет компилировать код на языке Scala и запускать симуляции. Здесь документация к плагину.

Gradle

Gradle также можно использовать для проектов Gatling на Java, Kotlin и Scala.

Gatling предоставляет официальный плагин gradle под названием io.gatling.gradle. Этот плагин позволяет запускать симуляции Gatling. Здесь документация.

Sbt

Sbt может использоваться только для проектов на языке Scala. Gatling предоставляет официальный плагин sbt под названием gatling-sbt. Этот плагин также позволяет запускать симуляции Gatling. Здесь документация.

Работа в IDE

Можно редактировать свои классы симуляций в Gatling с помощью любого текстового редактора с подсветкой. Но скорее всего вы будете работать в IDE:

IntelliJ IDEA

В IntelliJ IDEA Community Edition по умолчанию включена подсветка Java, Kotlin, maven и gradle.

Если хотите писать на Scala и, возможно, использовать sbt, нужно установить плагин Scala для IDEA Community Edition. Наверное, придется увеличить размер стека для компилятора scala, чтобы избежать ошибок переполнения стека. Рекомендуется установить значение Xss равным 100M.

VS Code

Желательно ознакомиться с официальной документацией по настройке VS Code:

Запуск Gatling и Recorder из IDE

Все демо-проекты maven, gradle и sbt содержат дополнительные хелпер-классы, которые можно использовать для запуска некоторых задач Gatling.

Чтобы запустить движок нагрузочного тестирования Gatling, нажмите правой кнопкой мыши на классе Engine в IDE. Отчеты по симуляциям запишутся в каталог target.

Чтобы запустить Recorder, нажмите правой кнопкой мыши на классе Recorder в IDE. Симуляции будут сгенерированы в каталог src/test/sources.

Базовые функции

Изучаем, как работает Gatling и Recorder, создаем первую симуляцию. Проведем нагрузочное тестирование простого облачного сервера и ознакомимся с элементами DSL (Domain Specific Language).

Выбор языка

Gatling предоставляет:

  • DSL для Java, начиная с версии Gatling 3.7 (подходит и для Kotlin)
  • оригинальный DSL для Scala.

При выборе языка тестов в Gatling рекомендуется придерживаться следующего правила:

  • Если целевые пользователи Gatling — Scala-разработчики, используйте Scala
  • Если Kotlin-разработчики, используйте Kotlin
  • Во всех других случаях используйте Java. Java популярный язык, ему нужно меньше ресурсов процессора для компиляции, и для Java легче настраивать maven и gradle.

Установка

Далее рассмотрим команды при установке пакета.

Кодировка

По умолчанию в Gatling используется кодировка UTF-8. Если хотите использовать другую кодировку, вам необходимо:

  • выбрать нужную кодировку для Recorder
  • настроить нужную кодировку в файле gatling.conf. Она будет использоваться для компиляции симуляций, сборки запросов и ответов.
  • убедиться, что кодировка вашего текстового редактора настроена правильно.

Тест-кейс

Рассмотрим HTTP-функции Gatling: симуляции, сценарии, фидеры, рекордеры, циклы и т. д.

Пример приложения

Для примера будем использовать приложение Computer-Database, развернутое здесь: http://computer-database.gatling.io.

Сценарий

Чтобы проверить производительность этого приложения, создадим сценарии, отражающие реальные действия пользователей.

Вот что чаще всего делает реальный пользователь с этим приложением:

  1. Пользователь заходит в приложение.
  2. Пользователь ищет «macbook».
  3. Открывает одну из моделей.
  4. Возвращается на главную страницу.
  5. Переходит по страницам.
  6. Создает новую модель.

Основы

Работа с Recorder

Чтобы облегчить создание сценария, будем использовать Recorder — инструмент, поставляемый вместе с Gatling, который позволяет записывать действия в веб-приложении и экспортировать их в Gatling-сценарий.

Recorder запускается скриптом в каталоге bin:

  • В Linux/Unix:

$GATLING_HOME/bin/recorder.sh

  • В Windows:

%GATLING_HOME%\bin\recorder.bat

После запуска Recorder можно настроить запись запросов и ответов в его GUI-интерфейсе.

Установите следующие параметры:

  • Recorder Mode в значение HTTP Proxy
  • пакет computerdatabase
  • Имя BasicSimulation
  • Follow Redirects? — да
  • Infer HTML resources? — да
  • Автоматические рефереры? да
  • Automatic Referers? — да
  • Remove cache headers? — да
  • No static resources — да
  • Выберите нужный format («Java 8»).

После настройки рекордера остается нажать «Start!» и настроить прокси в браузере для работы с Gatling Recorder.

Запись сценария

Теперь смотрим на приложение:

  1. Введите тег «Search».
  2. Перейдите на сайт http://computer-database.gatling.io.
  3. Найдите модели с «macbook» в названии.
  4. Выберите «Macbook pro».
  5. Введите тег ‘Browse’.
  6. Вернитесь на главную страницу.
  7. Несколько раз пройдитесь по страницам моделей, нажимая кнопку Next.
  8. Введите тег «Edit».
  9. Нажмите кнопку “Add new computer”.
  10. Заполните форму.
  11. Нажмите кнопку “Create this computer”.

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

Когда закончите воспроизведение сценария, нажмите кнопку Stop в интерфейсе Recorder.

Симуляция будет сгенерирована в папке user-files/simulations/computerdatabase в папке Gatling под именем BasicSimulation.java.

Разбор Gatling-сценария

Получили вывод (Java):

//package computerdatabase; // 1

// 2
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

public class BasicSimulationJava extends Simulation { // 3

  HttpProtocolBuilder httpProtocol = http // 4
    .baseUrl("http://computer-database.gatling.io") // 5
    .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") // 6
    .doNotTrackHeader("1")
    .acceptLanguageHeader("en-US,en;q=0.5")
    .acceptEncodingHeader("gzip, deflate")
    .userAgentHeader("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");

  ScenarioBuilder scn = scenario("BasicSimulation") // 7
    .exec(http("request_1") // 8
      .get("/")) // 9
    .pause(5); // 10

  {
    setUp( // 11
      scn.injectOpen(atOnceUsers(1)) // 12
    ).protocols(httpProtocol); // 13
  }
}

Цифрами в комментариях 1, 2 и далее — обозначены:

  1. Опциональный пакет.
  2. Необходимые импорты.
  3. Объявление класса. Обратите внимание, он является расширением Simulation.
  4. Общая конфигурация всех HTTP-запросов.
  5. BaseUrl, который будет добавляться ко всем связанным URL-ам.
  6. Стандартные HTTP-заголовки, которые будут отправляться со всеми запросами.
  7. Описание сценария.
  8. HTTP-запрос с именем request_1. Это имя будет отображаться в итоговых репортах.
  9. URL, к которому обращается запрос с помощью метода GET.
  10. Пауза.

Единицы продолжительности паузы (ожидания) по умолчанию выражаются в секундах, например,pause(5)эквивалентноjava.time.Duration.ofSeconds(5) в Java или pause(5.seconds) в Scala.

  1. Здесь прописываются сценарии, которые будут запущены в этой симуляции.
  2.  Объявляем, что вводим одного пользователя в сценарий, с именем scn.
  3.  Прикрепляем конфигурацию HTTP, объявленную выше.

Запуск Gatling

Запускаем второй скрипт, расположенный в каталоге bin:

  • В Linux/Unix:

$GATLING_HOME/bin/gatling.sh

  • В Windows:

%GATLING_HOME%\bin\gatling.bat

Должно появиться такое меню:

Do you want to run the simulation locally, on Gatling Enterprise, or just package it?
Type the number corresponding to your choice and press enter
[0] <Quit>
[1] Run the Simulation locally
[2] Run the Simulation on Gatling Enterprise Cloud
[3] Package the Simulation for Gatling Enterprise

Нажмите 1, затем Enter.

После этого появится меню с примерами симуляции:

Choose a simulation number:
[0] computerdatabase.BasicSimulation
[1] computerdatabase.advanced.AdvancedSimulationStep01
[2] computerdatabase.advanced.AdvancedSimulationStep02
[3] computerdatabase.advanced.AdvancedSimulationStep03
[4] computerdatabase.advanced.AdvancedSimulationStep04
[5] computerdatabase.advanced.AdvancedSimulationStep05

Нажмите 0, затем Enter. Нажмите Enter, когда Gatling попросит ввести описание тестового прогона.

По окончании симуляции в консоли появится ссылка на HTML-репорты.

Сложные функции Gatling

Изоляция процесса, настройка виртуальных пользователей, фидеры, проверки и циклы.

Мы уже прошли предыдущий раздел Базовых Функций и у нас есть рабочая симуляция, которую пробовали запускать. Далее будем постигать более продвинутые концепции и конструкции языка Domain Specific Language.

Файлы в примерах далее выложены на GitHub.

Шаг 1: Изоляция процессов

Сейчас наша симуляция представляет собой один большой монолитный сценарий. Поэтому сначала разделим этот сценарий на составные бизнес-процессы. Таким образом, вы потом сможете повторно использовать некоторые части сценария, и создавать сложные модели поведения, не усложняя их обслуживание.

В нашем сценарии есть три отдельных процесса:

  • search: поиск моделей по их имени
  • browse: просмотр списка моделей
  • edit: редактировать модель

Здесь мы храним эти цепочки в атрибутах одного класса, а также можете хранить их в константах (static final полях в Java, атрибутах объектов в Scala и Kotlin, перемещать их в другой класс и т.д.).

ChainBuilder search =
  // let's give proper names, as they are displayed in the reports
  exec(http("Home")
    .get("/"))
    .pause(7)
    .exec(http("Search")
      .get("/computers?f=macbook"))
    .pause(2)
    .exec(http("Select")
      .get("/computers/6"))
    .pause(3);

ChainBuilder browse = null; // TODO

ChainBuilder edit = null; // TODO

Теперь мы можем переписать наш сценарий, используя эти реюзабельные бизнес-процессы:

ScenarioBuilder scn = scenario("Scenario Name")
  .exec(search, browse, edit);

Шаг 2: Настройка виртуальных пользователей

Итак, мы научились тестировать нагрузку на сервер — но только с одним пользователем. Теперь увеличим количество пользователей. Определим две группы пользователей:

  • Обычные пользователи: они могут искать и просматривать модели.
  • Пользователи-администраторы: они могут искать, просматривать, а также редактировать модели.

В переводе на язык сценариев (Java):

ScenarioBuilder users = scenario("Users")
  .exec(search, browse);
ScenarioBuilder admins = scenario("Admins")
  .exec(search, browse, edit);

Чтобы увеличить количество симулируемых пользователей, достаточно изменить конфигурацию симуляции следующим образом:

{
  setUp(users.injectOpen(atOnceUsers(10)).protocols(httpProtocol));
}

Здесь мы прописали только 10 пользователей, потому что пока не хотим перегружать наше тестовое веб-приложение. Если хотите симулировать 3000 пользователей, то не обязательно чтобы они подключались одновременно. Реальные пользователи, скорее всего, будут подключаться к приложению постепенно.

В Gatling имеется функция rampUsers для моделирования такого поведения. Значение ramp указывает продолжительность, в течение которой пользователи будут подключаться «линейно».

В нашем сценарии пропишем 10 обычных пользователей и 2 администратора, и будем подключать их в течение 10 секунд, чтобы не перегружать сервер:

{
  setUp(
    users.injectOpen(rampUsers(10).during(10)),
    admins.injectOpen(rampUsers(2).during(10))
  ).protocols(httpProtocol);
}

Шаг 3: Использование динамических данных с помощью Feeders и Checks

Мы настроили нашу симуляцию на подключение нескольких пользователей, но все они ищут одну и ту же модель. Теперь протестируем ситуацию, когда каждый пользователь ищет разные названия моделей.

Нам нужны динамические данные, чтобы симулируемые пользователи не шли по одному и тому же сценарию поведения, и чтобы в итоге мы не получили поведение, полностью отличающееся от поведения реальной системы (из-за особенностей кэширования, JIT и т. д.). Именно в таком случае нужны фидеры (Feeders).

Feeders — это источники данных, содержащие все значения, которые можно использовать в сценариях. Существует несколько типов фидеров, самый простой из них — CSV Feeder: его будем использовать в нашем тесте.

Сначала создадим файл с именем search.csv и поместим его в папку user-files.

Этот файл содержит следующие строки:

searchCriterion,searchComputerName
Macbook,MacBook Pro
eee,ASUS Eee PC 1005PE

Затем декларируем фидер и используем его для подачи нашим пользователям вышеуказанных данных:

FeederBuilder.Batchable<String> feeder =
  csv("search.csv").random();// 1, 2

ChainBuilder search = exec(http("Home")
  .get("/"))
  .pause(1)
  .feed(feeder) // 3
  .exec(http("Search")
    .get("/computers?f=#{searchCriterion}") // 4
    .check(
      css("a:contains('#{searchComputerName}')", "href")
        .saveAs("computerUrl") // 5
    )
  )
  .pause(1)
  .exec(http("Select")
    .get("#{computerUrl}")) // 6
  .pause(1);

Объяснение (в комментариях в коде):

  1. Сначала создаем Feeder из csv-файла со следующими колонками: searchCriterion, searchComputerName.
  2. Поскольку стратегия Feeder по умолчанию — queue, будем использовать рендомную стратегию для этого теста, чтобы избежать «голодания» фидера.
  3. Каждый раз, когда пользователь достигает «шага подачи», выбирается случайная запись из фидера. У этого пользователя есть два новых атрибута сессии с именами searchCriterion и searchComputerName.
  4. Мы используем данные Session через язык Gatling Expression Language для параметризации поиска.
  5. Мы используем проверку CSS-селектора (также параметризованный с помощью Gatling Expression Language), чтобы записать («захватить») часть HTML-ответа, гиперссылку, и сохранить ее в сессии пользователя (Session) под именем computerUrl.
  6. Используем сохраненную гиперссылку для получения нужной страницы.

Подробнее о фидерах и HTTP Checks.

Шаг 4: Циклы

В процессе browse у нас много повторений при итерации по страницам. У нас четыре раза повторяется один и тот же запрос, с разными значениями параметров запроса. Не лучше ли сделать это по другому (чтобы не нарушать принцип DRY)?

Сначала извлечем повторяющийся блок exec в функцию. Ведь симуляции в Simulation — это обычные классы, так что при необходимости можем использовать все возможности Java:

private static ChainBuilder gotoPage(int page) {
  return exec(http("Page " + page)
    .get("/computers?p=" + page))
    .pause(1);
}

ChainBuilder browse =
  exec(
    gotoPage(0),
    gotoPage(1),
    gotoPage(2),
    gotoPage(3),
    gotoPage(4)
  );

Теперь мы можем вызвать эту функцию и передать нужный номер страницы. Но у нас все еще есть повторы, пора ввести еще одну встроенную структуру:

ChainBuilder browse =
  repeat(5, "n").on( // 1
    exec(http("Page #{n}").get("/computers?p=#{n}")) // 2
      .pause(1)
  );

Объяснение:

  1. Встроенный модуль repeat — это цикл, разрешаемый во время выполнения. Он принимает количество повторений и, опционально, имя счетчика, хранящегося в Session пользователя.
  2. Задав имя счетчика, мы можем использовать его в Gatling EL и получить доступ к n-й странице.

Подробнее о циклах.

Шаг 5: Проверка и управление отказами

До сих пор мы использовали check только для извлечения данных из html-ответа и сохранения их в сессии. Но check также удобен для проверки свойств в ответе. По умолчанию Gatling проверяет, является ли статус http-ответа 20x или 304.

Чтобы продемонстрировать управление отказами, введем check на условие, которое не выполняется случайным образом:

ChainBuilder edit =
  exec(http("Form").get("/computers/new"))
    .pause(1)
    .exec(http("Post")
      .post("/computers")
      .formParam("name", "computer xyz")
      .check(status().is(session ->
        200 + java.util.concurrent.ThreadLocalRandom.current().nextInt(2) // 2
      ))
    );

Объяснения:

  1. Сначала мы импортируем ThreadLocalRandom, чтобы генерировать случайные значения.
  2. Проверяем условие, которое было кастомизировано с помощью лямбды. Оно будет проверяться каждый раз, когда пользователь выполняет запрос, и случайным образом возвращать 200 или 201. Поскольку статус ответа — 200, проверка будет случайным образом выдавать fail.

Для обработки этого случайного отказа мы используем конструкции tryMax и exitHereIfFailed:

ChainBuilder tryMaxEdit = tryMax(2).on( // 1
  exec(edit)
).exitHereIfFailed(); // 2

Объяснение:

  1. tryMax проверяет заданный блок до n раз. Здесь мы проверяем максимум два раза.
  2. Если все проверки заканчиваются неудачей, пользователь выходит из сценария по команде exitHereIfFailed.

Подробнее.

Источник


Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

🔥 Популярное

💬 Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас