Хабрахабр

Магнитофон — инструмент для записи автотестов

Меня зовут Виктор Буров. Добрый день, уважаемые читатели. Я работаю разработчиком в компании ISPsystem и хочу поделиться опытом автоматизации тестирования.

Однажды мы подумали: почему бы не научить панель повторять действия тестировщика, ведь, по сути, все они превращаются в конкретные вызовы API. Так сложилось, что у нас превалировало ручное тестирование, и тестировщики тратили кучу времени на выполнение одних и тех же действий. Это бы позволило писать тесты людям даже без навыков программирования.

Чтобы тестировщик мог просто нажать кнопку создания теста, выполнить условия тест-кейса и по окончании нажать «завершить» — и всё, тест был готов! Мы решили написать модуль создания автоматических тестов. Потому что мы хотели, чтобы этот модуль был максимально адаптирован под наши продукты и использовал преимущество унифицированного интерфейса: чтобы сделанная запись выглядела как готовый тест-кейс. Простая идея, но реализовать ее оказалось непросто. Получившаяся в итоге система получила название «магнитофон».

Интерфейс модуля просмотра условий тест-кейса Это бы полностью избавило от ручной работы по написанию тестов.

Принцип работы

Все параметры запросов (HTTP-заголовки, переменные окружения, POST-данные, если такие есть) и весь ответ записывается в xml-файл. Каждой записи присваивается порядковый номер. Все запросы разделяются на модифицирующие и не модифицирующие. После записи теста многие из немодифицирующих запросов вырезаются, так как не влияют на выполнение тестов и только затягивают и запутывают процесс выполнения (отсюда пропущенные порядковые номера на скриншоте).

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

При воспроизведении запросы отправляются напрямую в API приложения, не используя браузер.

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

Пример записи одного вызова, сделанного магнитофоном:

Запись

<params> <param name="CONTENT_LENGTH">210</param> <param name="CONTENT_TYPE">application%2Fx%2Dwww%2Dform%2Durlencoded%3B%20charset%3DUTF%2D8</param> <param name="HTTPS">on</param> <param name="HTTP_ACCEPT">text%2Fhtml%2C%20%2A%2F%2A%3B%20q%3D0%2E01</param> <param name="HTTP_ACCEPT_LANGUAGE">en%2DUS%2Cen%3Bq%3D0%2E5</param> <param name="HTTP_CACHE_CONTROL">no%2Dcache</param> <param name="HTTP_CONNECTION">keep%2Dalive</param> <param name="HTTP_COOKIE">corelang5%3Dorion%3Aru%3B%20ispmgrlang5%3Dorion%3Aru%3B%20ipmgrlang5%3Dorion%3Aru%3B%20ipmgrses5%3Dbdd69179d627%3B%20ispmgrses5%3D14157f7bbc5e%3B%20menupane%3D30%5Faccount%2D1%253A30%5Fdomains%2D1%253A30%5Fwebserver%2D1%253A30%5Fantispam%2D1%253A30%5Fmaintain%2D1%253A30%5Ftool%2D1%253A30%5Fstat%2D1%253A30%5Fsrvset%2D1%253A30%5Fsysstat%2D1%253A30%5Fintegration%2D1%253A30%5Fset%2D1%253A30%5Fmgrhelp%2D1</param> <param name="HTTP_HOST">172%2E31%2E240%2E175%3A1500</param> <param name="HTTP_ISP_CLIENT">Web%2Dinterface</param> <param name="HTTP_PRAGMA">no%2Dcache</param> <param name="HTTP_REFERER">https%3A%2F%2F172%2E31%2E240%2E175%3A1500%2Fispmgr</param> <param name="HTTP_USER_AGENT">Mozilla%2F5%2E0%20%28X11%3B%20Ubuntu%3B%20Linux%20x86%5F64%3B%20rv%3A24%2E0%29%20Gecko%2F20100101%20Firefox%2F24%2E0</param> <param name="HTTP_X_REQUESTED_WITH">XMLHttpRequest</param> <param name="QUERY_STRING"/> <param name="REMOTE_ADDR"></param> <param name="REMOTE_PORT">38640</param> <param name="REQUEST_METHOD">POST</param> <param name="REQUEST_URI">%2Fispmgr</param> <param name="SCRIPT_NAME">%2Fispmgr</param> <param name="SERVER_ADDR">172%2E31%2E240%2E175</param> <param name="SERVER_NAME">172%2E31%2E240%2E175</param> <param name="SERVER_PORT">1500</param> </params>
<postdata>func%3Demaildomain%2Eedit%26elid%3D%26name%3Dtest%2Eemail%26owner%3Dusr%26ipsrc%3Dauto%26defaction%3Derror%26redirval%3D%26spamassassin%3Doff%26avcheck%3Doff%26clicked%5Fbutton%3Dok%26progressid%3Dfalse%5F1424243906672%26sok%3Dok%26sfrom%3Dajax%26operafake%3D1424243906673</postdata> <answer> <doc lang="ru" func="emaildomain.edit" binary="/ispmgr" host="https://172.31.240.175:1500" features="cba82687e7756e2c0195c88d4180f5d50" notify="0" theme="/manimg/orion/" css="main.css" logo="logo-ispmgr.png" logolink="" favicon="favicon-ispmgr.ico" localdir="default/"> <metadata name="emaildomain.edit" type="form" mgr="ispmgr" decorated="yes"> <form> <field name="name"> <input type="text" name="name" required="yes" check="domain" convert="punycode" maxlength="255"/> </field> // Поля формы <buttons> <button name="ok" type="ok"/> <button name="cancel" type="cancel"/> </buttons> </form> </metadata> <messages name="emaildomain.edit" checked="cba82687e7756e2c0195c88d4180f5d5"> <msg name="currentmonth">текущий месяц</msg> //Локализация </messages> <doc lang="ru" func="emaildomain.edit" binary="/ispmgr" host="https://172.31.240.175:1500" features="cba82687e7756e2c0195c88d4180f5d50" notify="0" theme="/manimg/orion/" css="main.css" logo="logo-ispmgr.png" logolink="" favicon="favicon-ispmgr.ico" localdir="default/"> <slist name="owner"> <val key="usr">usr</val> </slist> <slist name="defaction"> <val msg="yes" key="error">Сообщение об ошибке</val> </slist> <slist name="ipsrc"> <val msg="yes" key="auto">получить автоматически</val> </slist> <name/> <avcheck>off</avcheck> <owner>usr</owner> <ipsrc>auto</ipsrc> </doc> <id>test.email</id> <ok/> <tparams> <clicked_button>ok</clicked_button> </tparams> </doc> </answer> <localmacro> <macros name="mpre_HostIP" field="ipsrc">auto</macros> </localmacro>

Доработки (о чем мы не подумали заранее)

Ожидание

Человек может «просто подождать», компьютер — нет. Одна из первых проблем, которую должен был решить магнитофон, — написание вейтеров. Чего только народ не придумывал, чтобы дождаться завершения операции. Было реализовано ожидание фоновых задач и возможность добавить остановку на указанном шаге на заданное количество секунд.

Дозапись и редактирование шагов теста

Наверное, все помнят времена печатных машинок: одна ошибка — и приходится перепечатывать всю страницу.

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

Макросы для переменных

При выполнении тестов значения в передаваемых и проверяемых параметрах менялись в зависимости от сервера, на котором они были запущены. Пример таких данных — IP-адреса. Узнать их на этапе записи теста невозможно, поэтому я добавил систему макросов. Это позволило создавать тесты, не так жёстко привязанные к окружению. Недостаток решения в том, что после записи макросы надо указывать вручную.

Мы заметили её не сразу, так как тестировали магнитофон на ISPmanager, который использует нативные идентификаторы. Ещё одна проблема, существенно усложняющая работу с магнитофоном, — это использование не нативных ключей. Поэтому пришлось научить магнитофон не только получать идентификатор после создания записи или объекта (так как ID может меняться от запуска к запуску), но и подставлять его во все последующие запросы. Но в некоторых других панелях запись идентифицируется по уникальному ID.

Поддержка формата JUnit

Созданные магнитофоном тесты запускаются автоматически в среде непрерывной интеграции Jenkins. После выполнения тестов создаётся xml-файл, содержащий данные в формате JUnit. Чтобы файл корректно формировался, было введено ограничение на именование тестов. Например, тест User.Create.xml попадал в testsuite с именем User и, следовательно, testcase у него был Create. В случае ошибки к нему добавлялся дочерний узел failure с полным описанием ошибки.

Метрики

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

Хранилище тестов

Хранилище тестов в первую очередь решает проблему переноса готовых тестов на другие серверы. Ещё оно пригождается, когда тесты пишут несколько тестировщиков. Небольшая панель для хранения тестов Storage была разработана и развёрнута также на базе нашего COREmanager. В магнитофоне есть модуль синхронизации тестов с хранилищем. При написании нового теста или выгрузке тестов из хранилища они автоматически становятся недоступными к загрузке в хранилище, чтобы не возникло путаницы. После изменения теста у него повышается номер ревизии, чтобы в хранилище загружались только тесты после изменений.

Трудности (ну а куда же без них)

Использование магнитофона показало, что не все функции API следовали нашим же внутренним рекомендациям. В частности, не все функции возвращали идентификатор записи после её создания. Приходилось возвращаться в том числе к работающему коду и приводить его в соответствие с требованиями.

Панель подразумевает выполнение некоторых критических действий в монопольном режиме. Ещё одной проблемой стали deadlock. Это удалось определить только с помощью GDB (никто не вспомнил об этой особенности). И магнитофон, являясь частью той же панели, вызывая такие функции приводил к зависанию всей системы. Теоретически можно было оформить магнитофон не модулем, а отдельной панелью. К сожалению, не обошлось без костылей, потому что было принято решение при запуске тестов магнитофона выполнять эти функции в многопоточном режиме. Но мы не пробовали.

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

Заключение

Создание магнитофона помогло добиться повышения качества тестируемых продуктов. Сэкономлено время и ресурсы на обучение тестировщиков. Попутно магнитофон позволил провести review нашего API на соответствие внутренним рекомендациям, и, следовательно, сделать API чуточку более «логичным».

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть