Выпуск 30. Август 2015

Работаем с legacy. Паттерн «извлечение функции» и оценка результатов | Содержание | Обзор CPAN за июль 2015 г.

SWAT — простое тестирование веб-приложений

Позволяет тестировать веб-приложения используя специально подготовленную иерархию файлов

Введение

SWAT — дословно, в переводе — простое тестирование web приложений.

SWAT состоит из двух частей — DSL для написания smoke тестов и консольного клиента для запуска самих тестов.

Результат или отчет SWAT-теста выводится в TAP формате, что дает возможность переносить результаты тестов в различные системы мониторинга.

Отличительными особенностями SWAT является простота использования и минимальный набор зависимостей для установки, из которых только curl, пожалуй, является условно непредустановленным для линукс систем.

SWAT был придуман как практическая утилита, которой смогут воспользоваться как системные администраторы, далекие от глубин языка Perl, так и собственно разработчики web приложений.

Итак начнем описание SWAT c самого важного его компонента, а именно языка DSL для написания тестов.

DSL

DSL SWAT в первом приближении очень прост, посудите сами:

Пусть у нас есть web приложение myapp.com с набором http ресурсов /hello и /hello/world, требуется проверить что соответсвующие запросы к ресурсам возвращают успешный HTTP-статус 200 OK.

С помощью SWAT это делается так:

Создать структуру проекта приложения и описать ресурсы:

$ mkdir  myapp # создать директорию для проекта
$ mkdir myapp/hello # описать HTTP-ресурсы
$ mkdir myapp/hello/world

Определить ожидаемый контент:

$ echo 200 OK >> myapp/hello/get.txt
$ echo 200 OK >> myapp/hello/world/get.txt

Согласитесь, достаточно просто? Не трудно догадаться, что SWAT во время прогона тестов сделает два запроса GET /hello и GET hello/world и проверит, что вернулся статус 200 OK.

Вот как это будет выглядеть при запуске с консоли посредством консольного клиента SWAT:

$ swat ./myapp http://myapp.com
/home/vagrant/.swat/reports/http://myapp.com/hello/00.t ........
# start swat for http://myapp.com//hello | is swat package 0
# swat version v0.1.19 | debug 0 | try num 2 | ignore http errors 0
ok 1 - successfull response from GET http://myapp.com/hello
# data file: /home/vagrant/.swat/reports/http://myapp.com//hello/content.GET.txt
ok 2 - GET /hello returns 200 OK
1..2
ok
/home/vagrant/.swat/reports/http://myapp.com/hello/world/00.t ..
# start swat for http://myapp.com//hello/world | is swat package 0
# swat version v0.1.19 | debug 0 | try num 2 | ignore http errors 0
ok 1 - successfull response from GET http://myapp.com/hello/world
# data file: /home/vagrant/.swat/reports/http://myapp.com//hello/world/content.GET.txt
ok 2 - GET /hello/world returns 200 OK
1..2
ok
All tests successful.
Files=2, Tests=4,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.02 cusr  0.00 csys =  0.04 CPU)
Result: PASS

Однако, при всей кажущейся простоте SWAT обладает достаточно мощными средствами для расширения.

Основой алгоритм достаточно прост. Определили ресурсы, определили, что должно вернуться в ответе и прогнали тесты.

Однако SWAT обладает дополнительными возможностями, о которых я расскажу далее:

  • использование Perl-регекспов для валидации возвращаемого контента;
  • динамическая генерация проверочных утверждений;
  • изменение логики проверки посредством выполнения встраиваемого perl кода.

Итак, начнем с Perl-регекспов.

Использование Perl-регекспов

Помимо обычно plain текстовых проверок в SWAT можно задавать проверки с помощью регулярных выражений. Пусть у нас есть ресурс /version возвращающий версию приложения в виде version Foo.Bar.Baz , где каждый из элементов — целое число.

Используя SWAT и регекспы нетрудно написать тест для такого случая:

$ cat myapp/version/get.txt

200 OK
regexp: version (\d+\.\d+\.\d+)

$ swat myapp/ 127.0.0.1
/home/vagrant/.swat/reports/127.0.0.1/version/00.t ..
# start swat for 127.0.0.1//version | is swat package 0
# swat version v0.1.19 | debug 0 | try num 2 | ignore http errors 0
ok 1 - successfull response from GET 127.0.0.1/version
# data file: /home/vagrant/.swat/reports/127.0.0.1//version/content.GET.txt
ok 2 - GET /version returns 200 OK
ok 3 - GET /version returns data matching version (\d+\.\d+\.\d+)
# line found: 1.2.4
1..3
ok
All tests successful.
Files=1, Tests=3,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.01 cusr  0.00 csys =  0.03 CPU)
Result: PASS

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

Динамическая генерация проверочных утверждений

В самом простом случае SWAT получает проверочные утверждения, считывая их из текстового файла:

$ cat get.txt
FOO
BAR
BAZ
regexp: number d\+

При таком подходе проверочные данные детерминированы на этапе запуска тестов. А что если захочется генерить эти данные динамически? Тут нам помогут SWAT-генераторы.

SWAT-генераторы — это куски Perl-кода, которые возвращают ссылку на массив строк, представляющих проверочные утверждения. Поясню все, как обычно на примере:

Пусть у нас есть некий ресурс GET /ABC , возвращающий все буквы английского алфавита от A до Z :

$ GET /ABC

A
B
C
D
...

Давайте напишем для данного ресурса SWAT-тест. При решении «в лоб» можно просто перечислить все буквы английского алфавита в SWAT-файле, но это согласитесь не очень элегантное решение. Можно также использовать Perl regexp и написать так:

regexp:  ^[A-Z]$

Уже лучше, а что если хочется соблюсти компактность кода, но при этом не мучаться с регекспами, которые в определенных случаях могут быть достаточно сложными? Давайте просто сгенерим массив проверочных утвержений:

$ cat ABC/get.txt

generator:  [ ('A' .. 'Z') ]

Это и есть SWAT-генератор. Хочется отметить, что данный пример тривиален, но ничто не останавливает вас от использования любого валидного Perl-кода для генерации SWAT-тестов. Пусть, мы хотим проверить что отданный нам контент - список пользователей содержится в некоторой sqlite-базе, тогда можно написать так:

$ cat USERS/get.txt

use DBI; \
my $dbh = DBI->connect("dbi:SQLite:dbname=/app/data/users.db","",""); \
my $sth = $dbh->prepare("SELECT name from users"); \
$sth->execute(); \
my $results = $sth->fetchall_arrayref; \
[ map { $_->[0] } @${results} ]

Заметили символы \ в приведенном примере? В SWAT разрешены многострочные выражения при написании генераторов и Perl-выражений.

О Perl-выражениях и управлении проверочной логикой речь пойдет далее.

Perl-выражения и управление проверочной логикой

Perl-выражения в SWAT это просто вставки Perl-кода, которые вы можете использовать в тексте SWAT-тестов. Данный код будет выполнен в режиме <Perl evaled string> во время прогона тестов, приведу сначала абстрактный пример:

HELLO
code: print "THIS IS HELLO WORLD"
WORLD

Смысла в приведенном коде никакого он просто выведет на консоль строчку “THIS IS HELLO WORLD”, никак не повлияв на логику теста — будут выполнены проверки на наличие слов HELLO а затем WORLD .

Что бы понять чем же Perl-выражения могут быть полезны в SWAT, необходимо рассказать как проверочные утверждения будут выглядeть после обработки SWAT парсером.

Дело в том, что после парсинга, каждое SWAT-утверждение превращается в соответствующий assert модуля Test::More. Каждый, кто хоть раз писал юнит-тесты для собственных Perl-модулей, знаком с данным инструментом.

После парсинга SWAT-теста мы имеем дело по сути с тестом в формате Test::More, а значит мы можем использовать функции данного модуля для управления логикой теста, приведу показательные примеры:

RED
GREEN
code: skip("skip next check",1) # пропустить следующую проверку для цвета BLUE
BLUE
YELLOW
PUPRPLE
ONE
TWO
code: \
if ( $ENV{SKIP_COLORS} ) {    # пропустить следующие три проверки \
                              # если задана переменная окружения skip_colors \
    skip( "skip next check", 3 ) \;
}
BLUE
YELLOW
PUPRPLE

Обратившись к документации Test::More, можно найти много других интересных примеров функций, эскпортируемых данным модулем, которые могут быть нам полезны. Конечно, хочется подчеркнуть еще раз, что вы можете использовать любой Perl-кода при написании SWAT-генераторов и Perl-выражений, конкретные примеры можно найти на странице проекта SWAT.

Заключение

На этом я хотел бы закончить краткий экскурс в утилиту SWAT, предоставляющую DSL для написания smoke тестов web приложений. Не все фичи и тонкости раскрыты в данной статье, за полной документацией отправляйтесь на страницу проекта.

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

Спасибо!

Алексей Мележик


Работаем с legacy. Паттерн «извлечение функции» и оценка результатов | Содержание | Обзор CPAN за июль 2015 г.
Нас уже 1393. Больше подписчиков — лучше выпуски!

Комментарии к статье