Pull to refresh
94.51
ISPsystem
IT infrastructure management platforms

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

Reading time7 min
Views4.8K


Добрый день, уважаемые читатели. Меня зовут Виктор Буров. Я работаю разработчиком в компании 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 чуточку более «логичным».
Tags:
Hubs:
+18
Comments10

Articles

Information

Website
www.ispsystem.com
Registered
Founded
Employees
101–200 employees
Location
Россия