Статья подготовлена сотрудниками отдела тестирования в компании, где я работаю.
На хабре уже не первый раз пишут про 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
- Возможно, некоторые другие.
Статья большая, потому что подробная. В итоге должно получиться что-то вроде такого:
Автоматическая запись скрипта
Суть в том, что когда мы создаем скрипт для сайта, который мы тестируем методом черного ящика, мы не знаем всех тонкостей и особенностей его работы. Так, например, тот сайт, на базе которого в итоге получится мой скрипт, написан при помощи некоторого пакета 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.
Настоятельно рекомендую дать сразу всем элементам понятные имена. В моём случае это будут «Картинки» и «Залогинимся», соответственно.
Записываем скрипт при помощи HTTP Proxy Server
Когда подготовительные действия завершены, добавим на «верстак» необходимый элемент: WorkBench -> Add -> Non-Test Elements -> HTTP Proxy Server.
В нем много настроек, но нас интересует пока только порт. Если порт 8080 занят, можно выставить, например, 8089. Я на своей машине использую именно этот (8089). Так же мы видим, что по умолчанию в поле Target Controller стоит «use recording controller». Т.е. записываться лог будет именно туда.
Остальные поля трогать не будем, но некоторые из них нам понадобятся, когда мы получим чуть больше информации о нашем сайте.
После того, как выставили порт, идем в настройки браузера. Я банально использую IE. Сервис — Свойства обозревателя — Подключения — кнопка Настройка сети. Ставим галки «Использовать прокси-сервер …», вторую галку снимаем. Рекомендую заглянуть в «Дополнительно» и посмотреть, что написано в «Исключения». В моей практике в процессе тестирования сайт перенесли на новый домен, который оказался в исключениях. Ушло около получаса, чтобы разобраться, почему действия моего виртуального пользователя на тестируемом сайте не записываются, а всякие ссылки на яндекс, твиттер и фэйсбук прекрасно логируются. В общем, если там неожиданно оказался домен вашего сайта, сотрите.
В поле Адрес пишем «Localhost», а порт указываем как из JMetеr'а: «8089». Без кавычек всё, разумеется.
Теперь все готово для записи. Возвращаемся в JMeter на прокси и внизу можем нажать кнопку Start. После нажатия все действия пользователя в браузере начнут записываться в созданный нами Recording Controller «Залогинимся». Записывать действия будем в несколько шагов, т.к. скрипт может оказаться чрезмерно большим и его будет сложно редактировать. Так что первое, что мы сделаем, а после отладим, это авторизация пользователя на сайте.
Итак, нажимаем Start и проходим процедуру авторизации на сервере (у вас может её не быть, а у меня есть) и процедуру авторизации на сайте. Возвращаемся в JMeter и жмем Stop. Смотрим на Recording Controller: у него куча дочерних элементов. Это то, что мы послали на сервер, а сервер ответил. Изучаем и чистим.
Отладка скрипта
Отладка скрипта представляет собой удаление различных .jpg, .png и ссылок на сторонние ресурсы. У меня в скрипте больше половины таких сторонних ресурсов — это связи с различными социалками и яндекс картой. Всё это можно вычищать (клавишей delete). В целом, также можно вычистить .js. Главное найти запрос, который передает в своем теле учетные данные вашего пользователя. Ну и для красоты найти запрос, который ведет вас на страницу, на которой пользователь логинится. Таким образом, вместе они моделируют связку в действиях пользователя «зашел на страницу — залогинился».
Предположим, что нам повезло вычленить необходимые запросы. Ну, или нам кажется, что мы их вычленили. Дадим им читаемые имена! Чтобы проверить то ли мы вычленили, скрипт надо запустить. В моем случае, если запустить скрипт, то он выполнится с ошибками. Дело в том, что мне для тестирования нужно авторизоваться на сервере. Для этого добавим в верхушку дерева HTTP Autorization Manager (Thread Group – Add – Config Elements – HTTP Autorization Manager). Он интуитивно понятен. Записываем туда адрес нашего ресурса обязательно с http://, имя пользователя и пароль.
Если Менеджер Авторизации нужен для авторизации на сервере, то абсолютно точно при авторизации на сайте используются куки. Добавляем Cookie Manager после Менеджера Авторизации (TestPlan – Add – Config Elements — HTTP Cookie Manager). Этот элемент необходимо добавлять, пожалуй, всегда, если речь идет о том, что пользователю нужно залогиниться.
Прежде чем запустить и проверить скрипт добавим элемент View Results Tree (Катушка – Add – Listener – View Results Tree), в котором можно будет наблюдать выполнение. Этот элемент удобно располагать всегда внизу. Ах да, еще нужно в настройках браузера убрать галку «использовать прокси» — он пока нам не понадобится.
Итак, можно запустить. Запускаем (ctrl + r)!
В View Results Tree видим следующее:
Кажется, нам повезло. И даже если мы не залогинились, то, по крайней мере, запросы дошли до сервера. Чтобы убедиться, что пользователь был успешно залогинен, посмотрим в дереве на ответ. Нажимаем на Response Data. В ответе сервера ищем информацию, которая свидетельствует об успешной авторизации пользователя. В моем случае это будут имя пользователя, т.к. после авторизации оно высвечивается на странице.
Скрипт по-прежнему может нуждаться в чистке. Я, например, удалил из него HTTP Header Manager'ы. И без них всё работает отлично. Чтобы убедиться в нужности каждого элемента, его не обязательно сразу удалять, достаточно этот элемент отключить (ctrl + t).
Далее мы хотим привлечь к этому делу 3 пользователей. Для этого прежде выполним небольшой учебный пример по параметризации запросов. Параметризируем одного конкретного пользователя.
Параметризация
Для параметризации запросов добавим в самый верх User Define Variables. Thread -> Config Controllers -> User Define Variables. Внизу есть кнопка Add. Нажимаем ее, вбиваем две переменные, т.к. меняться у нас будут только два параметра: логин и пароль. Дадим им хорошие имена: userName и password. А в качестве значений впишем пока конкретные значения текущего пользователя.
Чтобы их использовать переходим в запрос Логин, и вместо конкретных значений пишем имена переменных в формате ${имя переменной}. В нашем случае записываем в поля Value для логина — ${userName}, для пароля — ${password}.
Для отладки передачи параметров добавим еще один элемент – Debug Sampler. Thread –> Add -> Samplers –> Debug Sampler. Его поставим после запроса Логин. В настройках элемента оставим только JMeter variables, остальные поставим в false. Это делам для того, чтобы отловить только наши переменные. Да и всё равно других нет.
Запускаем и смотрим в View Results Tree результаты. Должны видеть, что в качестве переменных передались именно наши значения, и запросы в целом вернули то, что нужно (см. выше).
Теперь можно передать данные 3 пользователей. Для этого воспользуемся CSV Data Set Config.
CSV Data Set Config
Я предлагаю создавать .csv файл в блокноте. Для пользователей файл должен представлять собой набор из 3х строчек вида «UserName;Password». Мой файл представлен на скрине ниже:
Далее добавим в дерево элемент CSV Data Set Config (Add – Config Elements – CSV Data Set Config). Добавим его не в катушку, а в тест-план, ниже пользовательских переменных. В качестве filename для файла нужно указать полностью путь к файлу и его имя. Ниже указать кодировку (на ваш выбор). Если все данные на английском, то поле можно оставить пустым. Ниже написать переменные, которые считаются из файла. Для нас это будут UserName и Password. В качестве разделителя нужно указать точку с запятой, так как в файле используется она. Ниже, для того, кто хоть немного владеет английским, не сложно перевести имена логических переменных. Нужно поставить в false повтор файла по достижении конца, а также остановку катушки.
Далее удалим подобные переменные из User Define Variables. То, что он останется пустым, это не страшно. После этого в самой катушке количество потоков (Number of Threrads) установим на 3.
Теперь можно запустить скрипт и наблюдать в Debug Sampler и View Results Tree результаты. Не забудьте проверить, те ли данные вернул сервер, есть ли в них имена ваших пользователей.
Добавляем фотографию в альбом
Теперь, когда наши пользователи научились логиниться, приступим к следующей части нашего скрипта. Научим их заливать в какой-нибудь определенный альбом нашего сайта фотографии. Для этого опять добавим в катушку Recording Controller, назвав его «Фотографии».
Чтобы сократить полученный скрипт, заранее авторизуемся пользователем на сайте и перейдем на страницу, на которой начнется непосредственно загрузка фотографии. После этого снова включим в настройках браузера прокси и воспользуемся элементом Proxy Server на верстаке (указав другой Recording Controller). Так же в URL Patterns to Exclude укажем расширения, которые нам не нужны в формате «*..ххх».
Start, заливаем в альбом фотографии, End. Приступаем к чистке скрипта. Точно также можно для красоты оставить лишь те запросы, которые образуют связку «зашел в альбом — добавил фотографию». У меня получилось так:
На самом деле, запрос «зашел в альбом» записан был вручную. Он не представляет собой ничего сложного: это GET запрос с указанием адреса страницы.
Обратим внимание на тело запроса, который отправляет на сервер файл. Единственное, что в нем представляет для нас ценность, — это путь и имя файла. Вот их мы и параметризируем, чтобы каждый пользователь заливал какую-то свою фотографию. Начнем с пути к файлу. Как таковой для тестирования он не представляет интереса. Вполне вероятно, что все фотографии будут у вас лежать в одной папке. Но в тесте он может встречаться много раз. Так что по правилам хорошего тона запишем его в переменную. Возвратимся к User Define Variables и добавим туда переменную filePath со значением пути до папки, в которой лежат фотографии, например, "** D:jakarta-jmeter-2.5.1images**". Именно со слэшем в конце, позже ясно будет для чего.
Как всегда, протестируем сначала скрипт на одном файле. Поэтому создадим еще одну переменную fileName, в качестве значения которой будет конкретное имя файла, например, "img.jpg".
Возвратимся в тело запроса. В разделе Send Files With the Request пишем путь уже таким образом: ${filePath}${fileName}. Если подставить в переменные указанные значения (value из user define variables), легко убедиться, что получается корректный путь. Посмотрим на параметры, которые передает запрос. Там тоже есть имя файла. Впишем вместо него ${fileName}.
Теперь, когда имитация пользователя в этой части закончена, добавим новый Debug Sampler. Подумаем на шаг вперед: если мы заставим катушку крутиться forever (пока не ставить!), то каждый пользователь будет логиниться по много-много раз, верно? Чтобы этого избежать, добавим в катушку логический элемент Only Once (Thread -> Add -> Logic Controllers -> Only Once Controller). Поместите его в соответствующее место над Recording Controller'ом, отвечающий за авторизацию пользователя на сайте, а сам контроллер перетащите в него как дочерний.
Отключите в браузере прокси. Запустите срипт. Если всё сделано правильно, то в выбранный альбом добавится новая фотография. Если что-то не так, посмотрите 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 и ответы сервера.
Изменяем аватарку
На деле это ничем не отличается от предыдущего параграфа. Точно также нужно залить на сервер фотографию. Поэтому делаем все также:
- создаем очередной recording controller
- настраиваем прокси
- делаем действия на сайте (записываем скрипт)
- чистим скрипт
- параметризуем для одной аватарки
- отлаживаем
- параметризуем для множества аватарок
В качестве имен аватарок я использовал тот же 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