47
Опыт разработки и тестирования RESTful JSON сервиса

Опыт разработки и тестирования RESTful JSON сервиса

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Опыт разработки и тестирования RESTful JSON сервиса

Опыт разработки и тестирования RESTful JSON сервиса

Page 2: Опыт разработки и тестирования RESTful JSON сервиса

Требования к системе

● Удобство для реселлеров● Возможность брендирования● Гибкость и возможность расширения за

счет подключаемых модулей

Page 3: Опыт разработки и тестирования RESTful JSON сервиса

Реализация

FRONTEND

BACKEND

API

Customer

Login

Domain

VPS

...

Page 4: Опыт разработки и тестирования RESTful JSON сервиса

RESTful API

● Ресурсы (объекты)● URI – идентификатор ресурса● HTTP методы (POST, GET, PUT, PATCH,

DELETE) ● Формат передачи данных на выбор (HTML,

XML, JSON, …)● Метаданные

Page 5: Опыт разработки и тестирования RESTful JSON сервиса

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 { … };

Page 6: Опыт разработки и тестирования RESTful JSON сервиса

Dancer

dancer/ +-- config.yml +-- dancer.pl +-- customer/ | +-- lib/ | | +-- customer.pm | +-- t/ +-- login/ | +-- lib/ | | +-- login.pm | +-- t/

...

...

+-- domain/ | +-- lib/ | | +-- domain.pm | +-- t/ +-- cpanel/ | +-- lib/ | | +-- cpanel.pm | +-- t/ +-- vps/ +-- lib/ | +-- vps.pm +-- t/

Page 7: Опыт разработки и тестирования RESTful JSON сервиса

Routes

get '/domain' => sub : Auth(

Admin Marketing Reseller

) {

Chimera::API::Domain->get(params());

};

Page 8: Опыт разработки и тестирования RESTful JSON сервиса

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

Page 9: Опыт разработки и тестирования RESTful JSON сервиса

Routes - Controllers

get '/domain' => sub : Auth(

Admin Marketing Reseller

) {

Chimera::API::Domain->get(params());

};

Page 10: Опыт разработки и тестирования RESTful JSON сервиса

ControllersChimera/API/ +-- Basket.pm +-- Basket/ | +-- Item.pm +-- Cpanel.pm +-- Cpanel/ | +-- Addondomain.pm | +-- SSL.pm +-- Customer.pm +-- Customer/ | +-- Service/ | +-- Service.pm | +-- User/ | +-- User.pm +-- Domain.pm ... +-- Utils.pm

Page 11: Опыт разработки и тестирования RESTful JSON сервиса

Server-side programsuse Dancer::Chimera qw(catch_output);

my %domain_data = catch_output('Chimera::API::Domain','create',%param

);return $domain_data{output} if $domain_data{error};

# Process output…;

Page 12: Опыт разработки и тестирования RESTful JSON сервиса

Тестирование

<sam> Doing the tests afterwards is like putting a condom on after you've come.

Page 13: Опыт разработки и тестирования RESTful JSON сервиса

Test-driven development

● Добавить тест● Запустить тесты: убедиться, что новые тесты

не проходят● Написать код● Запустить тесты: убедиться, что все тесты

проходят● Рефакторинг● Повторить

Page 14: Опыт разработки и тестирования RESTful JSON сервиса

Тестирование API

use Test::ChimeraAPI;

Test::ChimeraAPI::run_tests(

{

title => 'Create: normal mailbox',

call => [

POST => '/email' => \%mailbox_details,

],

expect => {

http_code => HTTP_CREATED,

data => { success => 1 },

},

},

);

Page 15: Опыт разработки и тестирования RESTful JSON сервиса

Тестирование API

t/ (master) $ prove -v api.t1..78ok 1 - Create: normal mailbox: HTTP codeok 2 - Create: normal mailbox data is hashref as expectedok 3 - Create: normal mailbox{success} data: scalar as expectedok 4 - Create: normal mailbox{success} data: is '1'ok 5 - Create: normal mailbox data all matches...

Page 16: Опыт разработки и тестирования RESTful JSON сервиса

Тестирование

1.Написать тест и код

2.Запустить тесты

3.Увидеть кучу непонятных ошибок...

4.Понять, что сервер не перезапустился...

5.Исправить ошибки

6.Вернуться к пункту 2

Page 17: Опыт разработки и тестирования RESTful JSON сервиса

Тестирование

1.Написать тест и код

2.Запустить тесты

3.Увидеть кучу непонятных ошибок...

4.Понять, что сервер не перезапустился...

5.Исправить ошибки

6.Вернуться к пункту 2

Page 18: Опыт разработки и тестирования RESTful JSON сервиса

Dancer::Test

● Test::ChimeraAPI::request()– request_remote() - if $ENV{CHIMERA_SERVER}

● LWP::UserAgent::request()

– request_internal()● Dancer::Test::dancer_response()

Page 19: Опыт разработки и тестирования RESTful JSON сервиса

Dancer::Test - плюсы

● Не нужно запускать сервер:– Держать открытую вкладку

– Ждать рестарта

– Получать ошибки соединения

– Не отвлекаешься от процесса кодирования

● Загружаются только нужные приложения

Page 20: Опыт разработки и тестирования RESTful JSON сервиса

Dancer::Test - минусы

● Условия менее близки к реальным● Загрузка приложений при каждом запуске

теста → общее время тестирования выше

Page 21: Опыт разработки и тестирования RESTful JSON сервиса

Test::Class

● Фреймворк для представления тестов в виде классов

● Удобно для тестирования ОО-кода● При работе с большим количеством тестов

Curtis (Ovid) Poe

http://www.modernperlbooks.com/mt/2009/03/organizing-test-suites-with-testclass.html

http://www.slideshare.net/Ovid/testing-with-testclass

Page 22: Опыт разработки и тестирования RESTful JSON сервиса

Test::Class - плюсы

● Однократная загрузка Dancer-приложений– Может пригодиться для любых “тяжёлых”

модулей

● Много других “плюшек”– Фазы подготовки / очистки

– Наследование

– Тестирование отдельных классов через prove

– Тестирование отдельных методов

– и т.д.

Page 23: Опыт разработки и тестирования RESTful JSON сервиса

Test::Class - минусы

● Требует изучения (в том числе и исходников)

● Нужна реорганизация тестов

Page 24: Опыт разработки и тестирования RESTful JSON сервиса

Test::Class - тесты

t/

+-- class.t

+-- lib/

+-- Email/

+-- Test/

+-- Create.pm

+-- Delete.pm

+-- Get.pm

+-- Patch.pm

+-- Put.pm

+-- Rename.pm

+-- API.pm

Page 25: Опыт разработки и тестирования RESTful JSON сервиса

class.t

#!/usr/bin/env perl

use lib::abs '../../../lib';

use our::way;

use Test::Class::Load lib::abs::path('lib');

Page 26: Опыт разработки и тестирования RESTful JSON сервиса

Удалённые системы

Тесты

API-сервер

domains cpanel vps

Сторонние APIRegistrar

API cPanel API VPS API

Page 27: Опыт разработки и тестирования RESTful JSON сервиса

Удалённые системы

● Взаимодействие по сети– Медленно

– Необходимо подключение к Интернет

– Поддержка тестовых серверов

● Тормоза самих систем– Создание VPS занимает ~1 мин

● Конфликты при одновременном запуске тестов

Page 28: Опыт разработки и тестирования RESTful JSON сервиса

Mock-тестирование

● Пишем тесты и код● Доводим до рабочего состояния с

использованием реальной удалённой системы

● Записываем ответы сервера● Подменяем записанными ответами

реальные

Page 29: Опыт разработки и тестирования RESTful JSON сервиса

Mock-тестирование - протоколы

● HTTP (LWP::UserAgent) – большая часть систем

● Другие

Page 30: Опыт разработки и тестирования RESTful JSON сервиса

Test::LWP::Recorder

● Запись ответов сервера в файлы $request_md5sum

● Подстановка записанных ответов

Page 31: Опыт разработки и тестирования RESTful JSON сервиса

Test::LWP::Recorder

GET http://foreign.api/something/:id - $resp1

PATCH http://foreign.api/something/:id - $resp2

GET http://foreign.api/something/:id - $resp1 (а должен быть $resp3)

Page 32: Опыт разработки и тестирования RESTful JSON сервиса

Test::LWP::UserAgent

● Inspired by Test::Mock::LWP::Dispatch by Yury Zavarin

● Активно (более-менее) разрабатывается● Расширяет возможности LWP::UserAgent● Содержит интересные и полезные фичи

http://www.perladvent.org/2012/2012-12-12.html

Page 33: Опыт разработки и тестирования RESTful JSON сервиса

Test::LWP::UserAgent – register_psgi

$useragent->register_psgi($hostname, $app);

Используется любой PSGI-совместимый фреймворк.

Например, Dancer :)

Page 34: Опыт разработки и тестирования RESTful JSON сервиса

Но...

Тесты

API-сервер

domains cpanel vps

Сторонние APIRegistrar

API cPanel API VPS API

Процесс

Page 35: Опыт разработки и тестирования RESTful JSON сервиса

Но...

Тесты

API-сервер

Процесс

API-сервер

domains cpanel vps

Сторонние APIRegistrar

API cPanel API VPS API

Page 36: Опыт разработки и тестирования RESTful JSON сервиса

В Dancer всё глобально!

● Конфигурация (settings в Dancer::Config)– Serializer

● Хуки (singleton Dancer::Factory::Hook->hooks)– Аутентификация

● Переменные (vars в Dancer::SharedData)– Используются внутри нашего API, не

определены в mocked API

Page 37: Опыт разработки и тестирования RESTful JSON сервиса

Инжекция mock-данных

● Test::ChimeraAPI::Mocking– Подготовка mocked классов в секции startup()

– Глобальная переменная $Mock::Something::API

● Mock-данные инжектированы в сам тестовый класс

● Mock-класс проверяет наличие данных и возвращает их в порядке timestamp или отправляет запрос к серверу

● Запись в файл при необходимости

Page 38: Опыт разработки и тестирования RESTful JSON сервиса

Юнит-тестирование

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

http://tinyurl.com/c4rweaw

Page 39: Опыт разработки и тестирования RESTful JSON сервиса

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;

}

Page 40: Опыт разработки и тестирования RESTful JSON сервиса

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();}

Page 41: Опыт разработки и тестирования RESTful JSON сервиса

Devel::Cover

● Оценка покрытия тестами● $^P ($PERLDB) == 0x104;

– Выключена оптимизация

● Не работают атрибуты :(

Page 42: Опыт разработки и тестирования RESTful JSON сервиса

Devel::Coverpackage 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

Page 43: Опыт разработки и тестирования RESTful JSON сервиса

Документация проекта

● POD● Pod::HTML5::Browser

Код:https://github.com/LoonyPandora/Pod-HTML5-Browser

Презентация:https://speakerdeck.com/loonypandora/documentation-for-fun-and-profit

Page 44: Опыт разработки и тестирования RESTful JSON сервиса
Page 45: Опыт разработки и тестирования RESTful JSON сервиса
Page 46: Опыт разработки и тестирования RESTful JSON сервиса

Спасибо!

Илья Чесноков <[email protected]>

Page 47: Опыт разработки и тестирования RESTful JSON сервиса

Вопросы?