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

2,662 views

Published on

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

Published in: Technology
  • Be the first to comment

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

  1. 1. Опыт разработки и тестирования RESTful JSON сервиса
  2. 2. Требования к системе● Удобство для реселлеров● Возможность брендирования● Гибкость и возможность расширения за счет подключаемых модулей
  3. 3. Реализация CustomerF Login BR AO API CN Domain KT EEND N D ... VPS
  4. 4. RESTful API● Ресурсы (объекты)● URI – идентификатор ресурса● HTTP методы (POST, GET, PUT, PATCH, DELETE)● Формат передачи данных на выбор (HTML, XML, JSON, …)● Метаданные
  5. 5. REST + Dancerpost /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 { … };
  6. 6. Dancerdancer/ ... +-- config.yml +-- dancer.pl +-- domain/ +-- customer/ | +-- lib/ | +-- lib/ | | +-- domain.pm | | +-- customer.pm | +-- t/ | +-- t/ +-- cpanel/ +-- login/ | +-- lib/ | +-- lib/ | | +-- cpanel.pm | | +-- login.pm | +-- t/ | +-- t/ +-- vps/ +-- lib/ ... | +-- vps.pm +-- t/
  7. 7. Routesget /domain => sub : Auth( Admin Marketing Reseller){ Chimera::API::Domain->get(params());};
  8. 8. Routes - Authenticationuse 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. 9. Routes - Controllersget /domain => sub : Auth( Admin Marketing Reseller){ Chimera::API::Domain->get(params());};
  10. 10. 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
  11. 11. 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…;
  12. 12. Тестирование<sam> Doing the tests afterwards is like puttinga condom on after youve come.
  13. 13. Test-driven development● Добавить тест● Запустить тесты: убедиться, что новые тесты не проходят● Написать код● Запустить тесты: убедиться, что все тесты проходят● Рефакторинг● Повторить
  14. 14. Тестирование APIuse Test::ChimeraAPI;Test::ChimeraAPI::run_tests( { title => Create: normal mailbox, call => [ POST => /email => %mailbox_details, ], expect => { http_code => HTTP_CREATED, data => { success => 1 }, }, },);
  15. 15. Тестирование APIt/ (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 1ok 5 - Create: normal mailbox data all matches...
  16. 16. Тестирование1.Написать тест и код2.Запустить тесты3.Увидеть кучу непонятных ошибок...4.Понять, что сервер не перезапустился...5.Исправить ошибки6.Вернуться к пункту 2
  17. 17. Тестирование1.Написать тест и код2.Запустить тесты3.Увидеть кучу непонятных ошибок...4.Понять, что сервер не перезапустился...5.Исправить ошибки6.Вернуться к пункту 2
  18. 18. Dancer::Test● Test::ChimeraAPI::request() – request_remote() - if $ENV{CHIMERA_SERVER} ● LWP::UserAgent::request() – request_internal() ● Dancer::Test::dancer_response()
  19. 19. Dancer::Test - плюсы● Не нужно запускать сервер: – Держать открытую вкладку – Ждать рестарта – Получать ошибки соединения – Не отвлекаешься от процесса кодирования● Загружаются только нужные приложения
  20. 20. Dancer::Test - минусы● Условия менее близки к реальным● Загрузка приложений при каждом запуске теста → общее время тестирования выше
  21. 21. Test::Class● Фреймворк для представления тестов в виде классов● Удобно для тестирования ОО-кода● При работе с большим количеством тестовCurtis (Ovid) Poehttp://www.modernperlbooks.com/mt/2009/03/organizing-test-suites-with-testclass.htmlhttp://www.slideshare.net/Ovid/testing-with-testclass
  22. 22. Test::Class - плюсы● Однократная загрузка Dancer-приложений – Может пригодиться для любых “тяжёлых” модулей● Много других “плюшек” – Фазы подготовки / очистки – Наследование – Тестирование отдельных классов через prove – Тестирование отдельных методов – и т.д.
  23. 23. Test::Class - минусы● Требует изучения (в том числе и исходников)● Нужна реорганизация тестов
  24. 24. Test::Class - тестыt/ +-- class.t +-- lib/ +-- Email/ +-- Test/ +-- Create.pm +-- Delete.pm +-- Get.pm +-- Patch.pm +-- Put.pm +-- Rename.pm +-- API.pm
  25. 25. class.t#!/usr/bin/env perluse lib::abs ../../../lib;use our::way;use Test::Class::Load lib::abs::path(lib);
  26. 26. Удалённые системы Тесты API-серверdomains cpanel vps Сторонние APIRegistrar cPanel API VPS API API
  27. 27. Удалённые системы● Взаимодействие по сети – Медленно – Необходимо подключение к Интернет – Поддержка тестовых серверов● Тормоза самих систем – Создание VPS занимает ~1 мин● Конфликты при одновременном запуске тестов
  28. 28. Mock-тестирование● Пишем тесты и код● Доводим до рабочего состояния с использованием реальной удалённой системы● Записываем ответы сервера● Подменяем записанными ответами реальные
  29. 29. Mock-тестирование - протоколы● HTTP (LWP::UserAgent) – большая часть систем● Другие
  30. 30. Test::LWP::Recorder● Запись ответов сервера в файлы $request_md5sum● Подстановка записанных ответов
  31. 31. Test::LWP::RecorderGET http://foreign.api/something/:id - $resp1PATCH http://foreign.api/something/:id - $resp2GET http://foreign.api/something/:id - $resp1 (адолжен быть $resp3)
  32. 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. 33. Test::LWP::UserAgent – register_psgi$useragent->register_psgi($hostname, $app);Используется любой PSGI-совместимыйфреймворк.Например, Dancer :)
  34. 34. Но... ТестыПроцесс API-сервер domains cpanel vps Сторонние API Registrar cPanel API VPS API API
  35. 35. Но... ТестыПроцесс API-сервер API-сервер domains cpanel vps Сторонние API Registrar cPanel API VPS API API
  36. 36. В Dancer всё глобально!● Конфигурация (settings в Dancer::Config) – Serializer● Хуки (singleton Dancer::Factory::Hook->hooks) – Аутентификация● Переменные (vars в Dancer::SharedData) – Используются внутри нашего API, не определены в mocked API
  37. 37. Инжекция mock-данных● Test::ChimeraAPI::Mocking – Подготовка mocked классов в секции startup() – Глобальная переменная $Mock::Something::API● Mock-данные инжектированы в сам тестовый класс● Mock-класс проверяет наличие данных и возвращает их в порядке timestamp или отправляет запрос к серверу● Запись в файл при необходимости
  38. 38. Юнит-тестированиеЮнит-тестирование – это тестированиекаждого неделимого блокафункциональности в изоляции – не тольковозвращаемых значений для различныхаргументов, но также взаимодействия этихблоков с другими частями приложенияпутём имитации работы этих частей. http://tinyurl.com/c4rweaw
  39. 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. 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. 41. Devel::Cover● Оценка покрытия тестами● $^P ($PERLDB) == 0x104; – Выключена оптимизация● Не работают атрибуты :(
  42. 42. 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
  43. 43. Документация проекта● POD● Pod::HTML5::BrowserКод:https://github.com/LoonyPandora/Pod-HTML5-BrowserПрезентация:https://speakerdeck.com/loonypandora/documentation-for-fun-and-profit
  44. 44. Спасибо!Илья Чесноков <chesnokov.ilya@gmail.com>
  45. 45. Вопросы?

×