Введение в JMeter

в 8:27, , рубрики: jmeter, тестирование, метки: ,

Статья подготовлена сотрудниками отдела тестирования в компании, где я работаю.
На хабре уже не первый раз пишут про JMeter, но статьи имеют довольно узкую направленность, либо сложны для понимания. Поэтому, эта статья будет интересная именно начинающим.

Введение

Как-то я начал осваивать новый инстурмент — JМeter — и не смог найти какого-то полноценного руководства как руководства к действию. Постепенно, разобравшись по некоторым довольно полезным статьям и блогам, пользовательской документации, я начал что-то понимать. И решил, что, возможно, я не один ищу то, с чего можно начать работать. Освоить некоторые принципы построения и логику самого инструмента. Так что вот — статья о том, как начать.
Так что в этой статье мы рассмотрим пример создания скрипта для 3 пользователей, которые хотят:
1. залогиниться;
2. добавить в какой-нибудь альбом новую фотографию;
3. поменять аватарку.
Как таковой — это обычный бизнес процесс для какой-нибудь социальной сети.
И для этих целей будут использованы такие встроенные компоненты:

  • HTTP Proxy Server
  • Recording Controller x3
  • User Define Variables
  • CSV Data Set Config x3
  • Constant Timer
  • Uniform Random Timer
  • HTTP Autorization Manager
  • HTTP Request x6
  • Debug Sampler х3
  • HTTP Cookie Manager
  • Once Only Controller
  • Возможно, некоторые другие.


Статья большая, потому что подробная. В итоге должно получиться что-то вроде такого:
c017f1f09f290a0fa142b4cb9edbc8b5.png


Автоматическая запись скрипта

Суть в том, что когда мы создаем скрипт для сайта, который мы тестируем методом черного ящика, мы не знаем всех тонкостей и особенностей его работы. Так, например, тот сайт, на базе которого в итоге получится мой скрипт, написан при помощи некоторого пакета Symphony2. Из-за неё отправка данных логин-пароль идет не прямо с формы на странице /login, а с некоторой несуществующей страницы /login_check. И ко всему этому отправляется еще одно пустое поле, которое для пользователя скрыто.
Обнаружить подобные подводные камни поможет HTTP Proxy Server (это, как и всё прочие, встроенный элемент). Эмулируя работу прокси сервера, он будет записывать все полученныеотправляемые запросы.

Подготовительные действия

Мы пока не будем добавлять HTTP Proxy Server в дерево теста. Обсудим, куда мы будем записывать полученные «шаги». Позже, когда мы добавим элемент в дерево, мы увидим, что есть несколько возможностей, куда именно записывать результаты. Их можно записать прямо в «катушку» (Thread), на «верстак» (Workbanch), либо в элемент «Recording Controller». Я советую воспользоваться последним способом. Во-первых, это позволит при необходимости отключить (ctrl+t) весь лог разом; во-вторых, так лучше отслеживается и формируется структура теста.
Все действия по добавлению и редактировнию происходят по нажатию правой кнопки мыши в контекстном меню. Созданные элементы можно просто перетаскивать (drag and drop).
Итак: Test Plan -> Add -> Threads ->Thread Group; Thread Group -> Add -> Logic Controller -> Recording Controller.
Настоятельно рекомендую дать сразу всем элементам понятные имена. В моём случае это будут «Картинки» и «Залогинимся», соответственно.
15bb271fb1ef8d13b8c0d94ba3319ef7.png

Записываем скрипт при помощи HTTP Proxy Server

Когда подготовительные действия завершены, добавим на «верстак» необходимый элемент: WorkBench -> Add -> Non-Test Elements -> HTTP Proxy Server.
В нем много настроек, но нас интересует пока только порт. Если порт 8080 занят, можно выставить, например, 8089. Я на своей машине использую именно этот (8089). Так же мы видим, что по умолчанию в поле Target Controller стоит «use recording controller». Т.е. записываться лог будет именно туда.
Остальные поля трогать не будем, но некоторые из них нам понадобятся, когда мы получим чуть больше информации о нашем сайте.
df806a35fb74dc3aac7b46f4dfb7421e.png
После того, как выставили порт, идем в настройки браузера. Я банально использую IE. Сервис — Свойства обозревателя — Подключения — кнопка Настройка сети. Ставим галки «Использовать прокси-сервер …», вторую галку снимаем. Рекомендую заглянуть в «Дополнительно» и посмотреть, что написано в «Исключения». В моей практике в процессе тестирования сайт перенесли на новый домен, который оказался в исключениях. Ушло около получаса, чтобы разобраться, почему действия моего виртуального пользователя на тестируемом сайте не записываются, а всякие ссылки на яндекс, твиттер и фэйсбук прекрасно логируются. В общем, если там неожиданно оказался домен вашего сайта, сотрите.
В поле Адрес пишем «Localhost», а порт указываем как из JMetеr'а: «8089». Без кавычек всё, разумеется.
795fceb9b55e67df06cbb39b501e9d61.png
Теперь все готово для записи. Возвращаемся в JMeter на прокси и внизу можем нажать кнопку Start. После нажатия все действия пользователя в браузере начнут записываться в созданный нами Recording Controller «Залогинимся». Записывать действия будем в несколько шагов, т.к. скрипт может оказаться чрезмерно большим и его будет сложно редактировать. Так что первое, что мы сделаем, а после отладим, это авторизация пользователя на сайте.
Итак, нажимаем Start и проходим процедуру авторизации на сервере (у вас может её не быть, а у меня есть) и процедуру авторизации на сайте. Возвращаемся в JMeter и жмем Stop. Смотрим на Recording Controller: у него куча дочерних элементов. Это то, что мы послали на сервер, а сервер ответил. Изучаем и чистим.
a3fb5932025bdbb8bde473227a043246.png

Отладка скрипта

Отладка скрипта представляет собой удаление различных .jpg, .png и ссылок на сторонние ресурсы. У меня в скрипте больше половины таких сторонних ресурсов — это связи с различными социалками и яндекс картой. Всё это можно вычищать (клавишей delete). В целом, также можно вычистить .js. Главное найти запрос, который передает в своем теле учетные данные вашего пользователя. Ну и для красоты найти запрос, который ведет вас на страницу, на которой пользователь логинится. Таким образом, вместе они моделируют связку в действиях пользователя «зашел на страницу — залогинился».
Предположим, что нам повезло вычленить необходимые запросы. Ну, или нам кажется, что мы их вычленили. Дадим им читаемые имена! Чтобы проверить то ли мы вычленили, скрипт надо запустить. В моем случае, если запустить скрипт, то он выполнится с ошибками. Дело в том, что мне для тестирования нужно авторизоваться на сервере. Для этого добавим в верхушку дерева HTTP Autorization Manager (Thread Group – Add – Config Elements – HTTP Autorization Manager). Он интуитивно понятен. Записываем туда адрес нашего ресурса обязательно с http://, имя пользователя и пароль.
246c61bc3cc8ef1ce7350931a009f99c.png
Если Менеджер Авторизации нужен для авторизации на сервере, то абсолютно точно при авторизации на сайте используются куки. Добавляем Cookie Manager после Менеджера Авторизации (TestPlan – Add – Config Elements — HTTP Cookie Manager). Этот элемент необходимо добавлять, пожалуй, всегда, если речь идет о том, что пользователю нужно залогиниться.
Прежде чем запустить и проверить скрипт добавим элемент View Results Tree (Катушка – Add – Listener – View Results Tree), в котором можно будет наблюдать выполнение. Этот элемент удобно располагать всегда внизу. Ах да, еще нужно в настройках браузера убрать галку «использовать прокси» — он пока нам не понадобится.
09d903bd3717d97ac545623830610536.png
Итак, можно запустить. Запускаем (ctrl + r)!
В View Results Tree видим следующее:
2990a49b3a74b9ec42f2ba5b3b227152.png
Кажется, нам повезло. И даже если мы не залогинились, то, по крайней мере, запросы дошли до сервера. Чтобы убедиться, что пользователь был успешно залогинен, посмотрим в дереве на ответ. Нажимаем на Response Data. В ответе сервера ищем информацию, которая свидетельствует об успешной авторизации пользователя. В моем случае это будут имя пользователя, т.к. после авторизации оно высвечивается на странице.
89a8a334039a213df29e6346aaec00b9.png
Скрипт по-прежнему может нуждаться в чистке. Я, например, удалил из него HTTP Header Manager'ы. И без них всё работает отлично. Чтобы убедиться в нужности каждого элемента, его не обязательно сразу удалять, достаточно этот элемент отключить (ctrl + t).
Далее мы хотим привлечь к этому делу 3 пользователей. Для этого прежде выполним небольшой учебный пример по параметризации запросов. Параметризируем одного конкретного пользователя.

Параметризация

Для параметризации запросов добавим в самый верх User Define Variables. Thread -> Config Controllers -> User Define Variables. Внизу есть кнопка Add. Нажимаем ее, вбиваем две переменные, т.к. меняться у нас будут только два параметра: логин и пароль. Дадим им хорошие имена: userName и password. А в качестве значений впишем пока конкретные значения текущего пользователя.
64f29cba08c40a5eb434cd5592d333c0.png
Чтобы их использовать переходим в запрос Логин, и вместо конкретных значений пишем имена переменных в формате ${имя переменной}. В нашем случае записываем в поля Value для логина — ${userName}, для пароля — ${password}.
3abd21fa63103acccbec21611115e63f.png
Для отладки передачи параметров добавим еще один элемент – Debug Sampler. Thread –> Add -> Samplers –> Debug Sampler. Его поставим после запроса Логин. В настройках элемента оставим только JMeter variables, остальные поставим в false. Это делам для того, чтобы отловить только наши переменные. Да и всё равно других нет.
060ae24c1bb7116dd9584958c9a51b9a.png
Запускаем и смотрим в View Results Tree результаты. Должны видеть, что в качестве переменных передались именно наши значения, и запросы в целом вернули то, что нужно (см. выше).
ab2dea0a6bf3bf094fda5db1c90dec99.png
Теперь можно передать данные 3 пользователей. Для этого воспользуемся CSV Data Set Config.

CSV Data Set Config

Я предлагаю создавать .csv файл в блокноте. Для пользователей файл должен представлять собой набор из 3х строчек вида «UserName;Password». Мой файл представлен на скрине ниже:
99d829bbeeb5f6c4310802411d87cbb6.png
Далее добавим в дерево элемент CSV Data Set Config (Add – Config Elements – CSV Data Set Config). Добавим его не в катушку, а в тест-план, ниже пользовательских переменных. В качестве filename для файла нужно указать полностью путь к файлу и его имя. Ниже указать кодировку (на ваш выбор). Если все данные на английском, то поле можно оставить пустым. Ниже написать переменные, которые считаются из файла. Для нас это будут UserName и Password. В качестве разделителя нужно указать точку с запятой, так как в файле используется она. Ниже, для того, кто хоть немного владеет английским, не сложно перевести имена логических переменных. Нужно поставить в false повтор файла по достижении конца, а также остановку катушки.
0e6afc60ec56cda8c1b2ec293e1dbf38.png
Далее удалим подобные переменные из User Define Variables. То, что он останется пустым, это не страшно. После этого в самой катушке количество потоков (Number of Threrads) установим на 3.
Теперь можно запустить скрипт и наблюдать в Debug Sampler и View Results Tree результаты. Не забудьте проверить, те ли данные вернул сервер, есть ли в них имена ваших пользователей.
1b4e52b8fed09f1f049e4eb2f7280b56.png


Добавляем фотографию в альбом

Теперь, когда наши пользователи научились логиниться, приступим к следующей части нашего скрипта. Научим их заливать в какой-нибудь определенный альбом нашего сайта фотографии. Для этого опять добавим в катушку Recording Controller, назвав его «Фотографии».
Чтобы сократить полученный скрипт, заранее авторизуемся пользователем на сайте и перейдем на страницу, на которой начнется непосредственно загрузка фотографии. После этого снова включим в настройках браузера прокси и воспользуемся элементом Proxy Server на верстаке (указав другой Recording Controller). Так же в URL Patterns to Exclude укажем расширения, которые нам не нужны в формате «*..ххх».
d7bc20766cd922782bef276dc4c859da.png
Start, заливаем в альбом фотографии, End. Приступаем к чистке скрипта. Точно также можно для красоты оставить лишь те запросы, которые образуют связку «зашел в альбом — добавил фотографию». У меня получилось так:
28afcd19ebc7b711c783c3cdb9d9b011.png
На самом деле, запрос «зашел в альбом» записан был вручную. Он не представляет собой ничего сложного: это GET запрос с указанием адреса страницы.
Обратим внимание на тело запроса, который отправляет на сервер файл. Единственное, что в нем представляет для нас ценность, — это путь и имя файла. Вот их мы и параметризируем, чтобы каждый пользователь заливал какую-то свою фотографию. Начнем с пути к файлу. Как таковой для тестирования он не представляет интереса. Вполне вероятно, что все фотографии будут у вас лежать в одной папке. Но в тесте он может встречаться много раз. Так что по правилам хорошего тона запишем его в переменную. Возвратимся к User Define Variables и добавим туда переменную filePath со значением пути до папки, в которой лежат фотографии, например, "** D:jakarta-jmeter-2.5.1images**". Именно со слэшем в конце, позже ясно будет для чего.
Как всегда, протестируем сначала скрипт на одном файле. Поэтому создадим еще одну переменную fileName, в качестве значения которой будет конкретное имя файла, например, "img.jpg".
23b590db04c057d0d48817886a1107a4.png
Возвратимся в тело запроса. В разделе Send Files With the Request пишем путь уже таким образом: ${filePath}${fileName}. Если подставить в переменные указанные значения (value из user define variables), легко убедиться, что получается корректный путь. Посмотрим на параметры, которые передает запрос. Там тоже есть имя файла. Впишем вместо него ${fileName}.
31d4483e50685da1fa518f82c134d51e.png
Теперь, когда имитация пользователя в этой части закончена, добавим новый Debug Sampler. Подумаем на шаг вперед: если мы заставим катушку крутиться forever (пока не ставить!), то каждый пользователь будет логиниться по много-много раз, верно? Чтобы этого избежать, добавим в катушку логический элемент Only Once (Thread -> Add -> Logic Controllers -> Only Once Controller). Поместите его в соответствующее место над Recording Controller'ом, отвечающий за авторизацию пользователя на сайте, а сам контроллер перетащите в него как дочерний.
c762b94cfdb723ff46aa620a622cc7cd.png
Отключите в браузере прокси. Запустите срипт. Если всё сделано правильно, то в выбранный альбом добавится новая фотография. Если что-то не так, посмотрите Debug Sampler в View Results Tree.

Параметризируем

Теперь можно сделать так, чтобы пользователи добавляли разные фотографии. Для этого создадим csv файл, в кототором будут содержаться только имена фотографий:
Img.jpg
Img1.jpg
Img2.jpg

Создадим CSV Data Set Config, перетащив его под другой CSV Data Set Config, укажем путь к этому файлу. В качестве переменной (variable Names) укажем fileName, а из пользовательских переменных (User Defined Variables) её удалим. Поле для разделителя оставим пустым. В этот раз повторять файл при достижении конца (Recycle on EOF) оставим на True, а останавливать катушку при достижении конца (Stop thread on EOF) — на False. Для красивой логики нашего теста перенесем фотографии в отдельную папку: " D:jakarta-jmeter-2.5.1imagesPhoto " и соответствующим образом изменим значение переменной filePath на filePath_Photo. Сделаем это и в тех местах, где переменная используется.
Запускаем тест! После чего смотрим, добавилось ли в альбом 3 фотографии (да, все пользователи должны иметь достаточно прав, на добавление фотографий в альбом). Если всё ОК, продолжаем дальше. Если нет — читаем Debug Sampler и ответы сервера.
813d89e44911fc7e1ac02f404e708d01.png


Изменяем аватарку

На деле это ничем не отличается от предыдущего параграфа. Точно также нужно залить на сервер фотографию. Поэтому делаем все также:

  1. создаем очередной recording controller
  2. настраиваем прокси
  3. делаем действия на сайте (записываем скрипт)
  4. чистим скрипт
  5. параметризуем для одной аватарки
  6. отлаживаем
  7. параметризуем для множества аватарок

В качестве имен аватарок я использовал тот же csv файл, но залил картинки в другую папку и создал новую переменную для нее: filePath_Avatars.
Если всё работает, то это хорошо. Если нет, смотрим в Debug Sampler.
Чтобы скрипт был больше похож на живого человека, нужно добавить задержки. Например, после загрузки фото на сервер, можно поставить Constant Timer на 3 секунды (3000ms), будто пользователь ждет, пока картинка загрузится на сервер. А для смены аватарки Gaussian Random Timer от 2 до 6 секунд, будко пользователь ищет и выбирает аватарку. Так же для большего правдоподобия в каждом HTTP Request можно поставить галку Retrieve All Embedded Resourced From HTML Files, означающую что со страницы будет загружаться всё возможное, как в обычном браузере.
Итак, предположим, что всё работает и всё отлично. Всё. Задача полностью выполнена. Теперь осталось нагрузить наш сайт на всю ночь. Вернемся в Thread и установим галку forever. Это значит, что скрипт будет выполняться, пока не случится событие «stop thread». В CSV Data Set Config'ах мы выставили возможность такого события в False. Значит, тест будет выполняться, пока его не остановит тестировщик руками (меню Run -> Stop). Итоговый скрин выложен в начале статьи.
Тест моделирует банальный бизнес-процесс для какой-нибудь социалки: пользователь зашел в сеть, залил в альбом фотографию, которая ему ну уж очень понравилась, со вчерашней вечерины и поменял свою аватарку на это (либо другое) фото. Поставив такой процесс на forever, мы получили 3 пользователей, которые заливают фотки и меняют на них аватарки. Процесс можно изменить, добавляя различные другие элементы. Например, заливать фотографии можно только одну, поставив Only Once, а вот менять аватарки бесконечно. Если пополнить базу до 1000 пользователей, запустить скрипт непосредственно с сервера, а также с локальных машин в офисе — это будет достаточно серьезная нагрузка на сервер приложения.
Возможно, следующая статья будет посвящена тестированию поиска и регулярным выражениям, либо оценке и интерпретации собранных данных.
Будем рады любому обмену опыта.

Автор: trurl123

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js