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

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

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

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

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



    В чем идея


    Идея в том, чтобы регрессивно проверять приложение на предмет “отвалившегося” функционала без затраты N часов на тесты в день. Добиться этого просто — если написать один тест на “абстрактную сущность” — то тест должен проходить со всеми её “конкретными” имплементациями. Если стандартизировать код — сделать разные его части имплементацией нескольких абстракций, например трех — весь код можно будет покрыть 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 надоевший баг.


    Шаг первый — деплой

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

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

    Первое что мы проверяем: “php -l” — все ли у нас парсится — без этого дальнейшее не имеет смысла. Второе что мы ищем в коде — это запрещенные вызовы: die, var_dump, ini_set, exit. Потом ищем с помощью обычного fgrep последствия кривого мержа: “<<<<<<<”, “>>>>>>”, “======” — такой мусор временами проскакивает, когда мержили руками и одно конфиликтное место не заметили и не разрешили конфликт.
    Так же мы ищем с помощью регулярных выражений следующее:
    • Методы длинной в много экранов кода.
    • Слишком вложенный код вида “5 вложенных if”
    • Слишком “загруженный код” вида print(preg_replace(‘/@/’, “/%/”, “a”.substr(1, 5, $lala).(int)(bool)$d)); — сложно читать, сложно писать и не хочется смотреть на такой код.


    Шаг третий — интерфейсная проверка кода

    Он разбит на несколько “подшагов” — проверка моделей, контроллеров, компонентов, универсальный 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% функционала” и подобным: мы не тестируем. Мы именно делаем проверку работоспособности.
    Это как проверка того, что лампочка горит в магазине — мы не проверяем её нагрев, не меряем излучаемый свет, не пробуем вкрутить в неподходящий патрон — мы проверяем, просто что она горит. Тоже самое мы делаем и с кодом. Простым, и не требующим поддержки способом.

    UPD. Пример реализации описанный здесь — просто пример и не более. Главное — идея стандартизации частей системы, отдельных сущностей. Стандартные «гайки» можно проверять одним способом проверки, а вот на нестандартные — придется придумывать разные.
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 46
    • +4
      Про тесты верстки было бы очень интересно почитать. И спасибо за статью.
      • +4
        Пожалуйста. Как только мы переведем тестирование верстки в состояние stable — напишем!
      • +1
        проверка — неотъемлемая часть) Спасибо.
        • 0
          Пожалуйста!
          Я тоже так считаю, ибо сломать старый функционал «случайно» — гораздо легче, чем написать новый баг, в новом функционале; ну с учетом того, что новый функционал пишут не левой ногой.
        • 0
          чем это лучше тестов контроллеров?
          • +1
            Тесты нужно поддерживать — писать новые и менять старые — а эта схема работает без затрат времени на тесты. В том и плюс!
            • 0
              Так по сути это тесты структуры базы? Ибо тесты контроллеров и должны выявлять минимум 500-ые ошибки. И покрывают они намного больше функционала. Да и разрабатывать просто — сделал руками запрос, и повторяй сколько хочешь пока тест не пройдет.
              • +1
                Это по сути — не тесты! У меня нет желания искать развалившийся код такоим сложным путем. Тесты — юнит, функциональные, интеграционные — проверяют бизнес-логику.
                В нашем CI нет задачи проверки бизнес логики — как мы её проверяем — отдельная тема.
                Задача этой схемы билда — проверка целостности, проверка того, что ничего не сломалось, то что раньше работало. Вот пример:
                Если Вы будете искать ошибки вида «juniur не имплементировал абстракный метод в одном из потомков» функциональными тестами, то цена нахождения такой ошибки слишком велика — N минут разработчика на тест, для поиска ошибки сделанной за 0 минут. В нашем случае 0 минут разработки тестов, на тупую ошибку.
                • 0
                  Я думаю то, что вы называете проверка работоспособности относится к smoke tests'ам
                  • 0
                    То, что вы делаете — это как раз интеграционные тесты. Когда-нибудь придёте к полноценным юнит-тестам, когда надоест разбираться «почему не работает» и «где не работает».

                    Хотя, конечно, интеграционные тесты — это лучше, чем ничего.
                • 0
                  Тесты не нужно поддерживать, если не меняется интерфейс. Если интерфейс всё-таки меняется, то придётся менять и скрипт «это у нас проверка, а не тестирование».
              • +2
                Вот она, золотая середина между полным отсутствием автоматической проверки и полным покрытием всего проекта тестами :) Как всегда, все гениальное — просто. Спасибо за идею!
                • 0
                  Пожалуйста! Вам спасибо за мнение!
                • 0
                  Ничего нового не узнал. То что Вы делаете очередная никому-не нужная белиберда, не важно для Yii она сделана или еще для чего-то.
                  Обычно работает немного не так все — делается хук на коммит в систему-контроля-версий(Code Sniffer+Black Mesa); этим обеспечен выровненный код-стайл и отсутствие сложных конструкций в любой не-локальной ветке разработчика.
                  Далее все заливается в какую-то ветку, и на ней проводится регрессивное тестирование. Затем эта ветка попадает в продакшн.
                  Какой-то псевдонаучный бред про то почему Вы и как используете Selenium я постарался пропускать, к делу это не относится.
                  Дальше Вы пишите — у нас мало «Unit-Тестов» с чем Вас и поздравляю. О чем статья в итоге так и не понял… Разьве что дифф скриншотов по верстке идея достаточно оригинальная(для меня по крайней мере).
                  • 0
                    Не узнали, а жаль. Есть понятие производственной стабильности, оно мало применятся к IT, а вот тут реально жаль. В описанным Вами методе он нарушается: «заливание в ветку» — это плюс к нестабильности (т.к. мерж может быть кривым).

                    Регрессивное тестирование — а у Вас есть 5 человек QA, которым Реально Приятно заниматься регрессивным тестированием? Уверен, что 90% QA такое не любят. А заставлять людей делать то что им неприятно — они делают это менее внимательно — вот еще минус к стабильности.

                    Про систему контроля версий и хук — а Вы серьезно думаете что я руками запускаю билды? Естественно нет. И точно не по хуку — более умным способом, чтобы не билдить каждый git push. Смысл есть билдить результат закрытого тикета, а не все что пушат. Билд нашего приложения длится 30 минут. Вот представьте, если пушат раз в минуту — за день наберется очередь билдов, которая будет разгребаться еще неделю!
                    • +1
                      Как уже писали ниже, пул-реквесты исключают кривые мержи.

                      Зачем каждый коммит? Все что в dev/master ветку пушится.

                      UPD 30 минут билд — что в него входит?
                      • 0
                        лишняя проверка никогда не лишняя.

                        30 минут:
                        * 2 схемы деплоя: итеративная миграция и с нуля (с установкой debian, конфигурированием и разверкой кода) — на это нужно 5 минут.
                        * selenium у нас обходит 100% интерфейса — на это нужно 15 минут.
                        * 1-5 минут нужно на имеющиеся unit и функциональные selenium тесты старых багов. Да, к сожалению selenium штука не быстрая
                        * 1-5 минут нужно на тесты библиотек.

                        Вот и 22-30 минут на билд. Билдим мы 3 бранча — master (stable), alpha (alpha-версия), beta (beta-версия).
                        • +1
                          30 минут — это очень много на самом деле.

                          ИМХО. Для каждого пуша в фича ветки — запускать smoke тесты. Библиотеки вынести отдельно.
                          После мержа в beta запускать «итеративную миграцию»(я так понимаю это обычный апдейт в репосе), чтобы на интеграционном хосте уже был результат и QA могли работать. Деплой с нуля, UI тестинг и функциональщина — это 3 отдельных задачи для дженкинса и они могут выполняться параллельно. Советую использовать плагин для Jenkins — Build Pipeline, в вашем случае очень пригодится
                        • 0
                          зачем если не секрет вы поднимаете новую виртуалку? А что вы будете делать когда этот процесс станет невозможен вследствии сложности проекта и завязки его на системные решения?
                          • 0
                            Этим мы по сути проверяем схему развертывания новой ноды в нашем кластере. По сути это тестирование автоматизации горизонтального масштабирования — у нас оно выполняется нажатие кнопки в панели полностью автоматически. Проверить правила автоматического развертывания сервисов для puppet, проверить, что конфиги в хранилище актуальны, и многое другое — это спасение от неожиданностей на проде. Неожиданностей вида — «а вот на эту новую ноду надо доустановить такой-то модуль php».

                            Проект и сейчас сильно завязан на системные решения, системное администрирование у нас сложное и по этому полностью автоматизировано — его тоже следует проверять. Развертка с нуля у нас — это установка 5и виртуалок и их настройка — минимальный размер кластера для нашего продукта.

                            Невозможен? А как может оказаться так, что продукт нельзя установить на новую машину?
                            • 0
                              это значит что затраты на поднятие виртуалки будут гораздо большие чем профит от развертывания вашего гипотетического кластера на 5 серверов. У вас 100500 серверов что надо при каждом билде тестить новый кластер? Оч. сомневаюсь…
                              • 0
                                У меня достаточно ресурсов чтобы для каждого билда поднять 5 виртуалок, собрать билд а потом их удалить.
                                • 0
                                  искренне рад за Ваши ресурсы, но вы так и не ответили на вопрос как же быть когда не у всех такой простой проект чтобы легким мановением руки поднимать вируалки и ставить на них необходимое окружение.
                                  • 0
                                    Поверьте, любой прект можно развернуть руками, любую работу автоматизировать. Любую медленную операцию — оптимизировать или кешировать.
                                    так что я не вижу особой проблемы в том, что Вы говорите.
                              • +1
                                Получается, что после изменений в php коде вы проверяете скрипты puppet, какой смысл? Не лучше ли будет проверять сборку «кластера» после ченжей в puppet скриптах? Другой вопрос, не лежат ли puppet скрипты вместе с общим кодом…
                                • +3
                                  Ну например — разработчик может в своем коде воспользоватся модулем php, которого еще нет в скриптах разворачивания.
                                  Значит нужно либо добавить модуль в скрипты, либо изменить код.
                                  Это один из множества примеров
                        • 0
                          Вы извратили мои слова как только могли. Пуш в удаленную ветку разработчика с хуком — не имеет ни малейшего отношения ни к описанной мной RC ни к master ни к билдам.
                      • 0
                        Достаточно было простых smoke тестов курлом после билда, если, как вы говорите, фаталы — 50х ошибки вылезут сразу же.

                        Для проверки Javascript и CSS валидности советую использовать Gruntjs с jshint и csslint.
                        • 0
                          Не уверен, что достаточно. Когда то мы тоже так делали, но вот итоговая эффективность проверки была гораздо ниже (примерно на 70%), т.к. нет явной проверки работы моделей — которую я описал. И курлом не всегда все можно «продергать» — особенно в случае полностью ajax-приложения, где url вызываемые нажатием на кнопку берется не просто из href, а конструируется более сложным способом.
                          • 0
                            Ну вот все сложные и «проблемные» схемы можно дергать курлом.

                            С моделями у нас когда-то тоже были такие проверки, но они подойдут только для несложных CRUD операций. Когда таких бесполезных тестов накопилось большое количество — от них отказались и начали мокать все обращения к бд, иначе скорость хромает. А что если будут сложные выборки на 2-3 таблицы, как их проверяете?
                            • –1
                              Таких тестов никогда не будет много — на все модели он один и бегает циклом по моделям. Один потому что все модели стандартны и похожи.
                              Выборки из 2-3 таблиц у нас не бывают, это запрещено. У нас высоконагруженый проект: Join-ы, Union-ы, subquery и прочее — убивает почти любой сервер БД на нагрузках 2000 хитов в секунду — это не раз проверено, так работаем не только мы, но и, например, Facebook. Так же выборки их N таблиц сходу ломают идею шардинга. Сложные запросы хороши в решениях уровня предприятия или малого проекта, но не в нашем случае.
                              Идея вобщем то не в том, как я сделал реализацию, а в том, что все части системы имеют стандартный вид и их очень просто проверять (не тестировать!) — один тест покрывает 5 сущьностей подходящих под один стандарт, например модели.
                              Это как ГОСТ на гайки. Если любая гайка имеет 6 граней — это легко проверить одним автоматом, а вот если бы гайки имели разное количество граней — то на каждый тип граней пришлось бы делать разные проверяющие автоматы.
                              Идея имено в стандартах на сущьности и в том что это легко проверять, а не в том как мы применили эту идею к нашему проекту.
                              • 0
                                Join-ы, Union-ы, subquery и прочее — убивает почти любой сервер БД на нагрузках 2000 хитов в секунду

                                Я думаю, что Вы врете. Можно пруф хоть какой-нибудь?

                                так работаем не только мы, но и, например, Facebook

                                Я могу предположить, что они по архитектурным причинам не могут их использовать.

                                Так же выборки их N таблиц сходу ломают идею шардинга.

                                Смотря как шардить.

                                У Вас данные денормализованы и Вам достаточно одного запроса? Или Вы делаете 2 селекта подряд и думаете, что это круто?
                        • 0
                          Ребята, а вам не кажется, что вы идете кривой дорожкой? Вместо того чтобы регулярками вылавливать факапы мерджей(лол, я реально удивился), стоило бы ввести код-ревью через пул-реквесты. Серьезно, попробуйте. И так далее, вплоть до виртуалки на отдельный бранч. И шаг (3) у вас, это что вообще такое? Ну, возможно я невнимательно прочитал. Но если бы практиковалось BDD — таких проблем бы в принципе не возникало.
                          • 0
                            «регулярками вылавливать факапы мерджей» — ревью естественно есть, и пул-реквесты тоже — мы используем gitlab. Просто людям свойственно ошибаться и забывать любой разработчик даже опытный, в определенных условиях менее внимателен и может допустить такую ошибку.
                            Моя задача не отказаться от тестирования, и не отказаться от код-ревью — задача передать тестировщикам рабочий код, чтобы они не занимались поиском фаталов, а проверяли бизнес логику. Конечная цель — стабильное приложение. Минимум косяков на проде, и не ценой замучанных регрессивными проверками QA :-)
                            • 0
                              Ну при код-ревью это само-собой видно, нет? Меня такая автоматизация и удивила :) А вообще, мы поступаем следующим образом. Решили сделать отдельный сервис, суть в чем. Через github api дергается список бранчей, и для каждого из бранчей тестер одним нажатием кнопки может поднять витруалку. Она поднимается, деплоится, порты www, ssh и vnc пробрасываются. Ему остается только протестировать, сказать что все ок, и удалить виртуалку. Тогда уже код вливается в master.
                              • 0
                                Лучше бы плагин на Jenkins :)
                                Поднимается локально у тестера на машине или на сервере?
                                • 0
                                  Jenkins не юзал) На сервере, тестеру только браузер нужен.
                            • 0
                              Недавно как раз интервью было с бадушниками, там все это обсуждалось
                            • 0
                              5xx — не нужно фаталить при кривых запросах, нужно давать пользователю осмысленную ошибку “что он делает не так”.

                              Спорный подход. Если хакер занимается подбором параметров чего бы поломать в системе, ему тоже писать осмысленную ошибку «что он делает не так»? Я специально ставлю по коду asserts, главное предназначение которых не дать разработчику криво вызвать функцию. Естественно для конечного пользователя идут обработки исключительных ситуаций и показываются ему ошибки, но только до тех пор, пока пользователь соблюдает протокол общение и не лезет в переменные GET/POST. Если программа вызывается способом, не предусмотренным разработчиками, ошибка обязательно должна быть, она должна прийти нам в Sentry, подлежит дальшейшему анализу и мы уже решаем что делать дальше — насколько вменяема и возможна данная ситуация, была ли попытка взлома и что делать дальше. Главное тут в том, что ошибки 500 показывают нам действительно внутренние ошибки…
                              • 0
                                Знать об ошибке, залогировать её и доложить в мониторинг — это одно. об ошибке bad request стоит докладывать — но это не повод нарушать http и на кривой запрос отвечать не 400, а 500 — как будто это внутреняя ошибка сервера. Тем более это не повод, чтобы код падал.
                                Мне ничего не мешает мониторить http status 400
                              • 0
                                Статья хороша, спасибо!

                                Начал писать комментарий, но в итоге родился целый пост — habrahabr.ru/post/191242/
                                • 0
                                  Идея понравилась, как раз совесть мучала из за не пишу никогда тесты. Для второго шага мы использовали pear.php.net/package/PHP_CodeSniffer/. Скорее всего возьму вашу идею на вооружение. Автору спасибо.
                                  • 0
                                    Вы примерно описали Smoke-тестирование
                                    ru.wikipedia.org/wiki/Smoke_test
                                    • 0
                                      Видимо в CRUD тесте вы пропустили редактирование данных и смену значения scenario.
                                      А в методе ModelClass::createDefault() вы формируете заведомо правильные данные на основе правил валидации, однако как вы проверяете достаточность правил валидации?
                                      И как поступаете с нестандартными правилами валидации?
                                      • +1
                                        Это всё, конечно, прекрасно (одних технологий и методик можно штук десять вписать в резюме). Но такими полумерами выстроена дорога в ад для тех, кто придёт к вам или вместо вас. Да и для вас самих, вы это поймёте в тот момент, когда ваше детище уже не сможет поддерживать ваш разросшийся код, но отказаться от этого детища будет жалко. Этот период мучений обычно занимает от полугода.

                                        Если коротко — кастомный полурабочий сложноизучаемый мусор, возникший от плохой лени.

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.