Структура фреймворка проектировалась таким образом, чтобы не создавать препятствий для тестирования кода на его основе. Это касается всех разновидностей контроллеров и стандартных сервисов, а также собственных функций фреймворка.
Способ тестирования зависит от вида использования сервисов, это может быть одноимённый класс со статическими методами вида Hleb\Static\Service::method() для встроенных сервисов фреймворка или DI, последнее как внедрение сервисов(и других объектов) в методы и конструктор класса.
Внедрение подходящих объектов согласно Dependency Injection распространяется во фреймворке только на создаваемые им объекты классов, таких как контроллеры, middleware, команды, события, а также объекты созданные сервисом под названием DI.
Простой пример демонстрационного контроллера с DI:
Допустим, необходимо убедиться, что контроллер возвращает текст 'OK', но при этом не отправлять сообщение в логи.
Здесь класс логирования заменён классом с таким-же интерфейсом, но его методы ничего не отправляют в лог.
Подразумевается, что для тестирования используется одна из специальных библиотек (например github.com/phhleb/test-o) и проверка будет реализована её средствами.
Теперь вызовем метод произвольного класса через сервис DI (именно сервис фреймворка, не название архитектурного метода):
В данном случае сервис логирования будет подставлен из контейнера и сообщение попадёт в лог. Изменим обращение к методу для его тестирования:
Теперь класс протестирован и логирование не произошло. Вы можете подменить таким образом любой объект для DI на специально созданный для этого собственный класс с нужным поведением, который будет удобно тестировать.
Встроенные сервисы фреймворка HLEB2 имеют способ обращения со статическими методами вида Hleb\Static\Service::method(). При использовании этого способа проще обращаться к сервисам, но затрудняется тестирование содержащих их модулей, хотя всё же возможно. На примере логирования:
В примере показано, как состояние сервиса было заменено на тестовый объект, а затем произведён откат к начальному значению. Чтобы такой способ нельзя было использовать вне тестов, в рабочем проекте, параметру конфигурации 'container.mock.allowed' файла /config/common.php выставлено значение false.
Для запуска тестов инициирующих ядро фреймворка, вам может понадобиться заменить частично или все сервисы контейнера на тестовые объекты. Для этого достаточно сделать свою реализацию и назначить её по условию (в примере это глобальная константа APP_TEST_ON):
Несколько встроенных функций фреймворка, упрощающих обращение к сервисам, таких как функция logger(), реализованы через тестируемые обращения к сервисам, в данном случае это обёртка над Hleb\Static\Log.
В контроллерах, middlewares, командах, событиях и других классах, унаследованных от Hleb\Base\Container, обращение к контейнеру может быть как $this-container. Если вы выбрали этот способ использования контейнера (смешивание различных способов в проекте выглядело бы странным), то для тестирования необходимо особым образом инициализировать конструктор объекта.