Автоматизируем автоматизированные тесты



Современный мир development operations предоставляет любому инженеру-автоматизатору прекрасную возможность использования CI-утилит, упрощая задачу ручного запуска автотестов на каждом из изменений в репозитории.

Но как быть, если ресурсов или времени на внедрение CI в процесс не хватает?

В этом деле нам помогут костыли смекалка и немного знаний Linux-систем. С помощью нехитрых манипуляций мы сможем автоматизировать запуск и доставку результатов автотестов. Итак, поехали.


Нужно оговориться, что автоматизировать можно запуск, как тестов, обращающихся к GUI(с использованием Chromedriver/Firefox и иже с ними), так и не работающих с графикой тестов(Phantom.js, ghostdriver, любые консольные тесты, которые работают с базами/"железом" серверов).


Итак, для этого нам понадобится:
1. Устройство, на котором будем запускать автотесты - 1 штук.
2. Умение работать с bash - 1 штук.
3. Умение работать с Cron - 1 штук.
4. Достаточное количество времени на разобраться с SSMTP/любым API для мессенджера - 1 штук.

Первое, что необходимо сделать - определиться со средой запуска для автотестов. В моем случае использовался Linux-дистрибутив(Ubuntu 14.10), и Chromedriver + Chrome.

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

И тут возникла первая проблема. Фразу "ребят, сделайте, пожалуйста, виртуалочку для автотестов", наши админы восприняли очень буквально и запилили голую Убунту с ssh-доступом. Пришлось просить их переустановить Ubuntu поднять на виртуалке X-сервер и настроить доступ через VNC. Можно пойти более простым путём и, например, установить TeamViewer, но мой вам совет, пользуйтесь VNC, он обладает значительно меньшим визуальным лагом и позволяет более гибко взаимодействовать с GUI удалённой машины.

Собственно,
Шаг 1. Конфигурация удаленной среды для запуска тестов.

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

Шаг 2. Перенос тестов на удалённую машину.

Для этого можно использовать систему контроля версий и забирать код руками, ssh-ась на сервер, но я написал простенький скрипт, который делает scp из необходимых директорий на удалённый сервер(нужно вытащить три разных файла и рассовать их по разным директориям, вводя пароль от пользователя на удалённом сервере). Учитывая, что разработку веду я сам - это заметно проще использования любой VCS.

Если же скрипт вам писать не охота - используйте команду копирования по ssh-протоколу:

scp -P 123 /path_to_tests_folder/* user@1.2.3.5:~/tests/

scp - команда копирования по протоколу ssh

Аргумент -P - указание порта, на который вы будете стучаться, в надежде увидеть на сервере ssh-демон(по умолчанию - 22, но лучше уточнять у ваших админов).

/path_to_tests_folder/* - указание абсолютного пути(хотя можно использовать и относительныый, начиная, например, с ~). Ну и звёздочкой отмечаем. что хотим скопировать все файлы из папки(ведь у нас же разнесенная структура тестов, правда?)

user@1.2.3.4.5:~/tests/ - указание имени пользования, под которым мы хотим стучаться на удалённый сервер, собственно, сам адрес сервера и через двоеточие - путь к конечной папке, в которую будут копироваться файлы. В моём случае - это папка tests. 

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

Шаг 3. Автоматизация запуска тестов.

Итак, тесты находятся на сервере, запускаются и наша основная задача - заставить их делать это без нашего участия.

Для этого создадим файл run_tests.sh в домашней директории пользователя. В этом файле будет храниться наш скрипт, с помощью которого тесты будут запускаться.

И вот, как он выглядит:


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

sudo chmod +x run_tests.sh

Итак, проверим корректность работы, введя

./run_tests.sh

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

Шаг 4. Настройка Crontab.

Cron - встроенный в большинство Linux-дистрибутивов журнал автоматического выполнения задач. Кроны бывают разные по типу и временным промежуткам для выполняемых задач.
Но сегодня мы будем разбирать crontab - надстройку над cron, позволяющую легко управлять запуском задач через периоды времени.

Для просмотра текущего состояния крона, необходимо выполнить команду

crontab -l

Вероятнее всего, вы увидите что-нибудь подобное:

Это означает, что ваша таблица крона пуста. Давайте внесем в нее команду для запуска нашего чудесного скрипта.
Для этого, предположим, что нам необходмо запускать нашу команду один раз в два часа.

Для редактирования файла crontab, необходимо выполнить команду

crontab -e

В некоторых случаях вам могут понадобиться привелегии супер-пользователя.

Итак, теперь всё, что нам необходимо - добавить маску для периода повторения запуска и исполняемую команду. Для простоты ориентирования во временных промежутках в маске, можно использовать эту прекрасную инструкцию:

 

Соответственно, если я хочу запускать свой скрипт каждые 2 часа(каждый чётный час, если быть точным), мне необходимо ввести следующую строку в конец файла, открытого на редактирование с помощью предыдущей команды

0 */2 * * * ~/./run_tests.sh

То есть, мы задаем запуск в ноль минут каждого чётного часа, каждого дня, каждого месяца, каждого дня недели.
И не забудьте нажать после этого Enter. Правила оформления требуют, чтобы перед EOF-символом в кронтабе обязательно присутстовала пустая строка.

Сохраняем этот файл с помощью редактора, которым он был открыт, и если проблем не будет, вы увидите строчку подтверждения

Installing new crontab...

Итак, тесты запускаются процесс идёт. Казалось бы, что может быть лучше.

Эээй, погодите-ка... А как узнать, что, например, все тесты прошли? Или как узнать, что они вообще были запущены?

И мы плавно подходим к "изюминке" нашей системы:

Шаг 5. Трекинг и доставка результатов.

У unittest-модуля Python есть предустановленный вывод, который помогает нам понять, сколько тестов прошло, по скольким был пасс и какие из них свалились с ошибками.

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

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

Для этого добавим создание файла лога и его заполнение результатами выполнения наших тестов. хранящихся в стандартном потоке вывода и потоке ошибок.


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

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

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

На настройке ssmtp долго стопориться не буду. Было много гугла, много StackOverflow и StackExchange, но настраивал в итоге вот по этому гайду: http://www.havetheknowhow.com/Configure-the-server/Install-ssmtp.html

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


Если всё сделано правильно, теперь каждые 2 часа после выполнения всего тест-рана к вам на почтовый адрес, указанный в скрипте, будут приходить письма с результатами запуска тестов.

Как вариант, строку с отправкой почты в скрипте можно заменить на POST-запрос с помощью утилиты curl, который бы дёргал по API любой из представленных на рынке мессенджеров и отправлял результаты в специализированный канал, тем более, что сделать это очень даже не тяжело. Главное - запастись терпением, чтобы разобраться в API того мессенджера, куда вы хотите отправлять результаты тестов.

Собственно, на этом всё. Надеюсь, эта статья смотивирует вас разобраться с утилитами и решениями, представленными в ней. А кто-то даже заимплементирует всё это в свой рабочий процесс. :)

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

5 комментариев:

  1. Серьёзно? Нет времени за 5 минут развернуть из WAD какую-нибудь готовую CI-систему, но есть куча времени разбираться с написанием и отладкой баш-скриптов с ssmtp.
    И всё это вместо дженкинса? Ведь это намного дольше и велосипеднее, чем засетапить джобу в дженкинсе, который умеет всё это и намного больше.

    ОтветитьУдалить
    Ответы
    1. Я не утверждаю, что такой подход будет служить полноценной заменой CI/CD-тулзам.
      Наоборот, я сторонник делать всё "по-человечески" с самого начала. Но бывают случаи, когда с процесс врываются требования вроде "Давай нагрузим этот сервер на коленке" или "Нам срочно нужны автотесты, есть 4 часа", а ресурсы для этого ограничены(и речь не только о времени).
      Это, если угодно, своего рода костыль, с которого со временем нужно перепрыгивать на CI, если автотесты себя хорошо зарекомендовали(а ведь так бывает не всегда).

      Удалить
    2. Понимаю.
      Просто твоё решение "на коленке" заняло у тебя явно больше времени, чем если бы ты разобрался в инструментах и сделал по-человечески.
      1. Код должен быть в репозитории. Особенно если на дворе 2016. Помимо всех очевидных плюсов VCS ты ещё получаешь возможность деплоить и автоматически обновлять свои тесты везде, где есть git или что там у вас.
      2. Если запускать тесты через nosetests с параметром "--with-xunit", он будет генерировать отчёты в формате jUnit/xUnit, который понимают все CI-системы вроде Jenkins/TeamCity. А это значит, что все проблемы с репортингом, его хранением, историей и графиками автоматически решаются твои инструментом. В Jenkins'e для этого надо лишь включить галочку Publish jUnit reports.
      3. Скачать wad-файл с https://jenkins.io/ и запустить java -jar jenkins.war займёт пару минут.

      btw, если поставишь xvfb и сделаешь export DISPLAY=:3, например, то браузер с автотестами будет запускаться в виртуальном окне и не будет мешать тебе писать баш-скрипты :)

      Удалить
  2. тесты у вас хранятся локально и переносятся вручную?!
    ведь "это заметно проще использования любой VCS", лол.
    это очень плохо, не учите людей такому.

    ОтветитьУдалить