Как тестировать приватные сервисы в Symfony.

2 версии Symfony подвержены рассогласованностью между сервисами и тестами. Вы используете Symfony 3.4 или 4.0? Вы хотите тестировать сервисы, но не знаете как получить их правильно? Сегодня мы посмотрим на возможные решения.

Если вы знаете проблему и ищите только решение, вы можете перейти сразу к решению для Symfony 4.1 или Symfony 3.4/4.0

Начиная с Symfony 3.4 все сервисы приватны по умолчанию. Это значит, что вы не можете получить сервис по средствам  $this->get(App\SomeService::class)  или  $this->container->get(App\SomeService::class) , but но только через конструктор.

Это хорошо, пока вы не захотите протестировать сервис

Когда мы запускаем тесты:

Это исключение остановит нас:

…Сделать его публичным… 

Хорошо:

И запустим тесты еще раз:

Работает!

Спускаемся в пахнущую кроличью нору

Как вы можете видеть, мы можем загружать десятки сервисов из  App\ с помощью двух строк. Но что бы тестировать 1 нам нужно добавить 2 дополнительные строки в конфигурацию.

Мы также можем извлечь это в тестовую конфигурацию   tests/config/config.yml, это просто, что бы скрыть «запах»

Или просто сделать все сервисы публичными:

это быстрое и простое решение, но оно не подходит для длительных и или больших проектов

Не беспокойтесь, вы не одиноки. Тут больше 36 результатов для запроса «symfony tests private services» на StackOverflow:

Что мы можем сделать?

1. В Symfony 4.1 с FrameworkBundle

Сейчас это исправлено в  Symfony 4.1 with Simpler service testing.

Вы используете:

просто обновите Symfony до версии 4.1.

2. В Symfony 4.1 без FrameworkBundle или Symfony 3.4/4.0

Но если вы не используете FrameworkBundle, то есть разрабатываете пакет и используете Symfony\Console и  Symfony\DependencyInjection?

В этом случае, разумно оставить всю конфигурацию как есть, не важно в каком мы окружении: в dev или test.

И тесты соответственно

Было бы здорово, если было бы одно место с условием, которое сделает весь код чистым и позволит нам тестировать сервисы. Это круто, верно? Как мы можем этого достигнуть? Идеи?

«Как насчет Compiler Pass?»

Конечно, Compiler Pass! Одна из самых лучших особенностей в Symfony — это возможности заложенные в архитектуре. Это позволяет вам писать чудесный, независимый и повторно используемый код по-умолчанию. После всего этого решение для Symfony 4.1 было закончено с Compiler Pass, that creates public ‘test.service-name’ aliases.

Вы можете писать ваши собственные обертки которые закрывают потребности вашего приложения (рекомендуется) или, если вы используете PHPUnit, использовать  Symplify\PackageBuilder:

Это позволяет удалить все  public:true из кода.

Где магия?

Вся эта «магия» в  PublicForTestsCompilerPass:

Этот код делает все сервисы публичными, когда запускается PHPUnit. Симпатично, не правда ли?

Это перевод этой статьи

Добавить комментарий