2. Требования к системе
● Удобство для реселлеров
● Возможность брендирования
● Гибкость и возможность расширения за
счет подключаемых модулей
3. Реализация
Customer
F Login
B
R
A
O
API C
N Domain
K
T
E
E
N
D
N
D ...
VPS
4. RESTful API
● Ресурсы (объекты)
● URI – идентификатор ресурса
● HTTP методы (POST, GET, PUT, PATCH,
DELETE)
● Формат передачи данных на выбор (HTML,
XML, JSON, …)
● Метаданные
5. REST + Dancer
post '/email/:domain' => sub { … };
get '/email/:domain' => sub { … };
get '/email/:domain/:mailbox' => sub { … };
put '/email/:domain/:mailbox' => sub { … };
patch '/email/:domain/:mailbox' => sub { … };
del '/email/:domain/:mailbox' => sub { … };
7. Routes
get '/domain' => sub : Auth(
Admin Marketing Reseller
){
Chimera::API::Domain->get(params());
};
8. Routes - Authentication
use base qw(Dancer::Chimera::App);
use Dancer qw(:syntax);
get '/domain' => sub : Auth(
Admin Marketing Reseller
){
Chimera::API::Domain->get(params());
};
Dancer::Plugin::Auth::Extensible
9. Routes - Controllers
get '/domain' => sub : Auth(
Admin Marketing Reseller
){
Chimera::API::Domain->get(params());
};
13. Test-driven development
● Добавить тест
● Запустить тесты: убедиться, что новые тесты
не проходят
● Написать код
● Запустить тесты: убедиться, что все тесты
проходят
● Рефакторинг
● Повторить
15. Тестирование API
t/ (master) $ prove -v api.t
1..78
ok 1 - Create: normal mailbox: HTTP code
ok 2 - Create: normal mailbox data is hashref as expected
ok 3 - Create: normal mailbox{success} data: scalar as expected
ok 4 - Create: normal mailbox{success} data: is '1'
ok 5 - Create: normal mailbox data all matches
...
16. Тестирование
1.Написать тест и код
2.Запустить тесты
3.Увидеть кучу непонятных ошибок...
4.Понять, что сервер не перезапустился...
5.Исправить ошибки
6.Вернуться к пункту 2
17. Тестирование
1.Написать тест и код
2.Запустить тесты
3.Увидеть кучу непонятных ошибок...
4.Понять, что сервер не перезапустился...
5.Исправить ошибки
6.Вернуться к пункту 2
19. Dancer::Test - плюсы
● Не нужно запускать сервер:
– Держать открытую вкладку
– Ждать рестарта
– Получать ошибки соединения
– Не отвлекаешься от процесса кодирования
● Загружаются только нужные приложения
20. Dancer::Test - минусы
● Условия менее близки к реальным
● Загрузка приложений при каждом запуске
теста → общее время тестирования выше
21. Test::Class
● Фреймворк для представления тестов в
виде классов
● Удобно для тестирования ОО-кода
● При работе с большим количеством тестов
Curtis (Ovid) Poe
http://www.modernperlbooks.com/mt/2009/03/organizing-test-suite
s-with-testclass.html
http://www.slideshare.net/Ovid/testing-with-testclass
22. Test::Class - плюсы
● Однократная загрузка Dancer-приложений
– Может пригодиться для любых “тяжёлых”
модулей
● Много других “плюшек”
– Фазы подготовки / очистки
– Наследование
– Тестирование отдельных классов через prove
– Тестирование отдельных методов
– и т.д.
23. Test::Class - минусы
● Требует изучения (в том числе и
исходников)
● Нужна реорганизация тестов
26. Удалённые системы
Тесты
API-сервер
domains cpanel vps
Сторонние API
Registrar
cPanel API VPS API
API
27. Удалённые системы
● Взаимодействие по сети
– Медленно
– Необходимо подключение к Интернет
– Поддержка тестовых серверов
● Тормоза самих систем
– Создание VPS занимает ~1 мин
● Конфликты при одновременном запуске
тестов
28. Mock-тестирование
● Пишем тесты и код
● Доводим до рабочего состояния с
использованием реальной удалённой
системы
● Записываем ответы сервера
● Подменяем записанными ответами
реальные
32. Test::LWP::UserAgent
● Inspired by Test::Mock::LWP::Dispatch by Yury
Zavarin
● Активно (более-менее) разрабатывается
● Расширяет возможности LWP::UserAgent
● Содержит интересные и полезные фичи
http://www.perladvent.org/2012/2012-12-12.html
33. Test::LWP::UserAgent –
register_psgi
$useragent->register_psgi($hostname, $app);
Используется любой PSGI-совместимый
фреймворк.
Например, Dancer :)
34. Но...
Тесты
Процесс
API-сервер
domains cpanel vps
Сторонние API
Registrar
cPanel API VPS API
API
35. Но...
Тесты
Процесс
API-сервер
API-сервер
domains cpanel vps
Сторонние API
Registrar
cPanel API VPS API
API
36. В Dancer всё глобально!
● Конфигурация (settings в Dancer::Config)
– Serializer
● Хуки (singleton
Dancer::Factory::Hook->hooks)
– Аутентификация
● Переменные (vars в Dancer::SharedData)
– Используются внутри нашего API, не
определены в mocked API
37. Инжекция mock-данных
● Test::ChimeraAPI::Mocking
– Подготовка mocked классов в секции startup()
– Глобальная переменная $Mock::Something::API
● Mock-данные инжектированы в сам
тестовый класс
● Mock-класс проверяет наличие данных и
возвращает их в порядке timestamp или
отправляет запрос к серверу
● Запись в файл при необходимости
38. Юнит-тестирование
Юнит-тестирование – это тестирование
каждого неделимого блока
функциональности в изоляции – не только
возвращаемых значений для различных
аргументов, но также взаимодействия этих
блоков с другими частями приложения
путём имитации работы этих частей.
http://tinyurl.com/c4rweaw
39. Mocking в юнит-тестах
package Provisioner;
use Provisioner::Mapper;
my $provisioner_mapper;
__PACKAGE__->reset_provisioner_mapper;
sub reset_provisioner_mapper {
shift->provisioner_mapper('Provisioner::Mapper');
}
sub provisioner_mapper {
if ($_[1]) { $provisioner_mapper = $_[1] };
return $provisioner_mapper;
}
sub create {
my ($self, $serviceplan) = @_;
my $class = $self->provisioner_mapper($serviceplan->codename);
return $class->new;
}
40. Mocking в юнит-тестах
sub provision_regrade_check_sp_is_passed_to_provisioner :Tests {
my $self = shift;
Provisioner->provisioner_mapper(Chimera::UnitTest::Mock::Generic->new([
{
method => 'mapping',
input => ['cpanel_shared_hosting'],
output => 'Chimera::UnitTest::Mock::Provisioner::CheckRegradeMethodCall'
},
]));
my($order, $action) = $self->_place_order($self->basket());
my $processed = Chimera::API::Action->process($action);
Provisioner->reset_provisioner_mapper();
}
41. Devel::Cover
● Оценка покрытия тестами
● $^P ($PERLDB) == 0x104;
– Выключена оптимизация
● Не работают атрибуты :(
42. Devel::Cover
package Dancer::Chimera::App;
use attributes;
my %attrs;
sub MODIFY_CODE_ATTRIBUTES {
my ($package, $subref, @attrs) = @_;
$attrs{ refaddr $subref } = @attrs;
return;
}
…
my $subref = sub : Auth(MyRole) { … };
…
http://tinyurl.com/bptkr9a - багрепорт в perl5.porters
43. Документация проекта
● POD
● Pod::HTML5::Browser
Код:
https://github.com/LoonyPandora/Pod-HTML5-Browser
Презентация:
https://speakerdeck.com/loonypandora/documentation-for-fun-and-profit