Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Yii, постоянная интеграция — как не сломать все

Anna | 31.05.2014 | нет комментариев

Мы Зачастую экспериментируем с архитектурой, кодом, продуктивностью. Непрерывно добавляем новейший функционал. Мы понемногу обвязываем Yii своей “архитектурной” прослойкой — шардинг, работа с временно недостижимыми данными, многообразные кеши и многое другое. Да, плод нашей работы, когда он будет заврешен, пойдет в Open Source.

Задача используемой у нас Постоянной Интеграции (Continuous Integration, CI) — не тестирование. Задача CI — обезопасится от разорительных изменений в следствие рефакторинга, добавления нового функционала, изменений архитектуры. Также мы защищаемся от “плохого кода”, Зачастую повторяющихся багов, “кривых” merge.

Для своего CI мы используем Jenkins под Debian. Время на развертку CI я затратил 12 часов — до всецело рабочего состояния. На поддержку CI я не трачу ни минуты в день — я не пишу тесты на всякую мелочь, не практикую TDD. Тем не менее, CI работает и выручает нас от тупых ошибок.

“Давайте будем внимательней”/”Давайте не делать ошибок” — взывал я к разработчикам, но это помогало лишь временно и то не на все 100%. Людям характерно заблуждаться, забывать, делать оплошности. Нет, я не изобрел “серебряную пулю” для web-планов и даже маленьку пульку для Yii — я придумал как стабилизировать свое приложение. Ваше приложение отличается от моего и мои способы у Вас могут не трудиться, да и не обязаны — я же делал их не для Вашего приложения, если мои способы тружусь у Вас — примите это как Диво либо как везение. Но идея такого CI будет трудиться всюду. Каждого лишь идея.

В чем идея

Идея в том, Дабы регрессивно проверять приложение на предмет “отвалившегося” функционала без затраты N часов на тесты в день. Добиться этого легко — если написать один тест на “абстрактную сущность” — то тест должен проходить со всеми её “конкретными” имплементациями. Если стандартизировать код — сделать различные его части имплементацией нескольких абстракций, скажем 3 — каждый код дозволено будет покрыть 3мя проверками. Да, именно “проверками”, а не тестами — я не тестирую функционал, я проверяю, что “код работает, не падает, не фаталит”. При положительном коде редко ломается бизнес-логика так, Дабы не вызвать неизбежной ошибки. По крайней мере у нас. Мы усердствуем писать код так — если логика работает правильно — она работает, если нет — кидается FatalException либо происходят другие неизбежные ошибки. Я считаю данный “жесткий” путь правильным, т.к. напротив будет дюже трудно искать сломавшуюся логику.

Мы стандартизировали код до следующих абстракций: модель (она теснее абсолютно стандартна в Yii и имеет абсолютно внятный интерфейс с способами find, save, delete). контроллер (он тоже абсолютно типовой), экшен (action), компонент, библиотека.

Если с моделями все легко, то с контроллерами и экшенами пришлось повозится. Мы решили, что всякий внешний вызов (http, console) не должен вызывать неизбежной ошибки (http >= 500): нет сущности — значит 404, косой запрос — значит 400, нет доступа — 403. Если Ваш контроллер фаталит при обращении к нему с несуществующей id либо с какими либо еще кривыми параметрами — это неверное поведение с точки зрения протокола http — оплошность пользователя — это 4xx, а не 5xx — не необходимо фаталить при кривых запросах, необходимо давать пользователю осмысленную ошибку “что он делает не так”.

Собственно проверка контроллеров и была построена по этому тезису — конструируем модуль, контроллер, дергаем action — глядим что случилось — ExceptionPage404 — это типично (данные то мы в $_GET не передали), а вот если FatalException либо PHP Error — это теснее нехорошо — тест не прошел.

Компоненты для Yii, которые мы пишем мы тоже стандартизировали. В нашем случае всякий компонент — это растяжение присутствующего функционала Yii. Скажем, добавление шардинга, всеобщий кеш БД. Такой функционал единовременно имплементирует две абстракции — модель Yii и наш компонент раширения. Проверяется он тоже 2 раза — на примере всех моделей, и отдельно как компонент.

Библиотеки — это написанный нами вовсе “левый” функционал, не имеющий отношения к Yii, а реализующий только какой-то частный случай логики, Почаще каждого — взаимодействие с другими сервисами нашей сервис-ориентированной архитектуры. Проверки и тесты на них — тема для отдельной статьи, скажу лишь одно — мы проверяем их как отдельные планы в нашем CI и изготавливаем “интеграционные тесты” внутри основного приложения.

Реализация на нашем примере

У нас 4 шага сборки:

  • Деплой, миграции, установка/обновление зависимостей — она не имеет отношения к описанной выше идее, легко скажу что оно есть.
  • Проверка качества кода
  • Интерфейсная проверка кода — имплементация описанной выше идеи.
  • Малое число Unit-тестов на Зачастую всплывающие баги (как легко phpunit, так и selenium phpunit). Они весьма редко “поддерживаются” либо добавляются — следственно я наприсал “не трачу N часов в день на тесты” — я трачу от силы 1 час в месяц на написание 1 теста, на 1 наскучивший баг.
Шаг 1-й — деплой

Выполняется проверка в 2х вариантах — миграция с предыдущей версии (одинаковой нынешнему состоянию продакшина) и развертка с нуля (с автоматизированной установкой виртуалных машин, механической конфигурацией puppet, разверткой приложения и базы)
Ничего определенного не скажу, т.к. это не касается данной статьи и вовсе иная история.

Шаг 2-й — качество кода

Первое что мы проверяем: “php -l” — все ли у нас парсится — без этого последующее не имеет смысла. Второе что мы ищем в коде — это запрещенные вызовы: die, var_dump, ini_set, exit. Потом ищем с поддержкой обыкновенного fgrep итоги кривого мержа: “<<<<<<<”, “>>>>>>”, “======” — такой мусор подчас проскакивает, когда мержили руками и одно конфиликтное место не подметили и не позволили раздор.
Так же мы ищем с поддержкой регулярных выражений следующее:

  • Способы длинной в много экранов кода.
  • Слишком вложенный код вида “5 вложенных if”
  • Слишком “загруженный код” вида print(preg_replace(‘/@/’, “/%/”, “a”.substr(1, 5, $lala).(int)(bool)$d)); — трудно читать, трудно писать и не хочется глядеть на такой код.
Шаг 3-й — интерфейсная проверка кода

Он разбит на несколько “подшагов” — проверка моделей, контроллеров, компонентов, многофункциональный selenium-проверки (да, и такое тоже есть! чуть ниже расскажу), интеграционные тесты с библиотеками.

Детально расскажу о самом простом и самом увлекательном. Самое примитивное — модели.
Любая модель должна: сохранятся, выбиратся, удалятся. Она именно для этого и существует. Намеренно для этого теста мы добавили в всякую модель статический способ, создающий “дефолтную валидную модель” — модель которую дозволено сделать, сберечь, удалить из БД, проходящую валидацию.
На самом деле мы не писали в 250 моделях 250 способов для создания таких моделей. Мы написали один способ у родителя — он вычленяет из rules параметры вылидации и заполняет поля валидными значениями. Потратил я на это — 2 часа.

В выводе для всякой модели в цикле мы делаем приблизительно следующее:

$model = ModelClass::createDefault(); //создаем дефолтную модель
$this->assertNotNull($model); //создалась?
$this->assertTrue($model->save()); //сохранилась?
$pk = $model->getPk(); //выбираем primary key
$loaded = ModelClass::model()->findByPk($pk); //ищем модель по этому primary key
$this->assertNotNull($loaded); //нашли?
$this->assertTrue($model->delete()); //удаляется?
$this->assertIsNull(ModelClass::model()->findByPk($pk)); //удалили?

Этой не хитроумной проверкой мы сделали следующее: удостоверились, что шардинг прослойка работает, кеш БД не мешает типичной работе, таблица в БД типично смигрировала и эта модель в эту таблицу сохраняется ( тригеры не падают).

Самое увлекательное же — selenium проверки.
Мы изучили наш интерфейс и пришли к счастливому итогу — он абсолютно стандартизирован. Есть 4 основных варианта взаимодействия с пользователем:

  • Смена всеобщей страницы
  • Смена Таба
  • Открытие диалогового окна
  • Отправка формы в диалоговом окне

Первые три пункта автоматизировались весьма легко — теги A и Button меняющие глобальную страницу имеют css-класс global, меняющие таб — имеют признак data-tab, открывающие диалог — имеют признак data-msgbox. Нам было довольно сделать 3 вложенных цикла: меняет страницу (тупо кликает на кнопку), меняет таб (тоже жмет на кнопку), открывает диалог (и тоже легко нажатие). На всяком из вложенных этапов мы проверяем — изменился ли контент страницы, поменялся ли контент в div-е для табов, открылся ли диалог. Заодно собираем из браузера возникшие ошибки js.
С формами было несколько хитрее. Нам пришлось добавить к элементам формы признаки data-type со значениями допустимых валидных данных — data-type = “email”,“anyString”, “checkboxChecked”, “phone”, “anyFile”, и другие. И вот! Формы стандартизированы и мы имеем всеобщий интерфейс для всех input-ов — в поля с валидными email мы заполняем email, в поля с phone — телефон, и так по каждому полям. Отправляем форму и проверяем, что диалог закрылся без ошибок — значит данные сохранились. Потом повторяем все тоже самое с невалидными данными, скажем в поле email пишем телефон — и проверяем что форма не отправилась, а оплошность для пользователя возникла.
На добавление признаков в поля форм я потратил около 1,5 часа. И у нас не немного форм — легко это простая работа и если сесть и сделать — то это не длинно.

Таким вот нехитрым (а может и хитроумным) способом мы проверили каждый UI на предмет:

  • Фаталов при открытии страниц, табов, окон
  • Фаталов при отправке валидных и невалидных форм.
  • Что формы сохраняются с валидными данными
  • Что формы выдают ошибки с не валидными данными.
Юнит-тесты и selenium-тесты

Добросовестно скажу — их немного, дюже немного. Их мы добавляем только тогда когда возник повторявшийся баг и в следующий раз тестировщики сказали “ну вот вновь не работает!”
Мы никогда не меняем ветхие, написанные тесты — мы разрабатываем приложение с учетом обратной совместимости. Это необходимо не только ради тестов — приложение имеет API для мобилок/десктопов и оно обязано быть обратно совместимым.

И что дальше?

Чуть позднее мы стандартизировали наш js-код и покрыли его (спасибо за testit товрищу titulusdesiderio — мы адаптировали его под запуск из под nodejs и там тестируем свой js)
Еще позднее мы покрыли тестами css html верстку — проверяли развалившуюся верстку с поддержкой diff-а скриншотов, на предмет кривизны.
Обо каждому этом я расскажу отдельно, если Вам безусловно увлекательно.

P.S. Раньше чем бранить с фразами “это не тестирование”, “оно покрывает 5% функционала” и сходственным: мы не тестируем. Мы именно делаем проверку работоспособности.
Это как проверка того, что лампа горит в магазине — мы не проверяем её нагрев, не меряем излучаемый свет, не пробуем вкрутить в неподходящий патрон — мы проверяем, легко что она горит. Тоже самое мы делаем и с кодом. Простым, и не требующим поддержки методом.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB