Twig_Environment в классе обслуживания приводит к DIC RuntimeExtension только при модульном тестировании в Symfony 2.8.

Я использую Twig_Environment для рендеринга писем в формате html для отправки. У меня есть класс NotificationService, который используется другими службами для отправки этих писем.

При обычном использовании все работает, но после обновления до версии 2.8 юниттест дает ошибку: Symfony\Component\DependencyInjection\Exception\RuntimeException: You have requested a synthetic service ("kernel"). The DIC does not know how to construct this service

Я отладил StackTrace, и проблема, похоже, в Twig_Environment (который использует file_locator, который вводит kernel)

/**
 * Notification Service Class
 *
 * @DI\Service("app.service.notification")
 */
class NotificationService extends Generic
{
    /**
     * @var \Twig_Environment
     */
    protected $twig;

    /**
     * @var \Swift_Mailer
     */
    protected $swiftMailer;

    /**
     * @var string
     */
    protected $mailTemplate = 'VendorAdminBundle:Email:system2.html.twig';

    /**
     * @param \Swift_Mailer     $swiftMailer
     * @param \Twig_Environment $twig
     *
     * @DI\InjectParams({
     *      "swiftMailer" = @DI\Inject("mailer"),
     *      "twig"   = @DI\Inject("twig")
     * })
     */
    public function __construct(\Swift_Mailer $swiftMailer, \Twig_Environment $twig)
    {
        $this->twig          = $twig;
        $this->swiftMailer   = $swiftMailer;
    }

    /**
     * Send notification mail to Manager
     * @param UserEntity $manager
     * @param array      $contacts
     */
    public function notifyManager(UserEntity $manager, array $contacts)
    {
        $subject = 'Lorem Ipsum';
        $templateFile = "AppBundle:Email:notifyManager.html.twig";
        $templateContent = $this->twig->loadTemplate($templateFile);
        $body = $templateContent->render(array(
            'user'      => $manager,
            'contacts'  => $contacts,
            'subject'   => $subject,
        ));

        $this->sendMail($body, $subject, $manager);
    }
}

Любые указатели на то, как решить эту проблему?

РЕДАКТИРОВАТЬ: (по запросу)

class NotificationTest extends DoctrineTestCase
{
    /**
     * @var \App\Service\Notification
     */
    protected $service;

    public function setUp()
    {
        $this->markTestSkipped('Problem with twig env');

        $this->loadFixturesFromDirectory(__DIR__ . '/DataFixtures');
        $this->loginUser('admin', $this->getUser(1));
        $this->service = $this->container->get('neos.service.notification'); // <-- exception thrown here
    }

    [test methods]
}   

РЕДАКТИРОВАТЬ2:

/**
 * Class DoctrineTestCase.
 *
 * This is the base class to load doctrine fixtures using the symfony configuration
 */
class DoctrineTestCase extends TestCase
{
    /**
     * @var \Symfony\Component\DependencyInjection\Container
     */
    protected $container;

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    protected $em;

    /**
     * @var string
     */
    protected $environment = 'test';

    /**
     * @var bool
     */
    protected $debug = true;

    /**
     * @var string
     */
    protected $entityManagerServiceId = 'doctrine.orm.entity_manager';

    /**
     * Constructor.
     *
     * @param string|null $name     Test name
     * @param array       $data     Test data
     * @param string      $dataName Data name
     */
    public function __construct($name = null, array $data = array(), $dataName = '')
    {
        parent::__construct($name, $data, $dataName);

        if (!static::$kernel) {
            static::$kernel = self::createKernel(array(
                'environment' => $this->environment,
                'debug' => $this->debug,
            ));
            static::$kernel->boot();
            static::$kernel->getContainer()->set('kernel', static::$kernel); //<--- Added - but doesnt help
        }

        $this->container = static::$kernel->getContainer();
        $this->em = $this->getEntityManager();
    }

    /**
     * Executes fixtures.
     *
     * @param \Doctrine\Common\DataFixtures\Loader $loader
     */
    protected function executeFixtures(Loader $loader)
    {
        $purger = new ORMPurger();
        $executor = new ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    /**
     * Load and execute fixtures from a directory.
     *
     * @param string $directory
     */
    protected function loadFixturesFromDirectory($directory)
    {
        $loader = new ContainerAwareLoader($this->container);
        $loader->loadFromDirectory($directory);
        $this->executeFixtures($loader);
    }

    /**
     * Returns the doctrine orm entity manager.
     *
     * @return object
     */
    protected function getEntityManager()
    {
        return $this->container->get($this->entityManagerServiceId);
    }
}

РЕДАКТИРОВАТЬ 3: Получение ядра, похоже, иногда менялось в прошлом. см. http://symfony.com/doc/master/cookbook/testing/doctrine.html

я изменил свой конструктор с:

public function __construct($name = null, array $data = array(), $dataName = '')
{
    parent::__construct($name, $data, $dataName);

    if (!static::$kernel) {
        static::$kernel = self::createKernel(array(
            'environment' => $this->environment,
            'debug' => $this->debug,
        ));
        static::$kernel->boot();
        static::$kernel->getContainer()->set('kernel', static::$kernel); //<--- Added - but doesnt help
    }

    $this->container = static::$kernel->getContainer();
    $this->em = $this->getEntityManager();
}

to:

public function __construct($name = null, array $data = [], $dataName = '')
{
    parent::__construct($name, $data, $dataName);

    self::bootKernel();

    $this->container = static::$kernel->getContainer();
    $this->em = $this->getEntityManager();
}

но, к сожалению, это не исправляет RuntimeException, когда тесты используют Twig_Env.


person Rufinus    schedule 19.12.2015    source источник
comment
Возможно, эта страница окажется полезной.   -  person Radu Murzea    schedule 20.12.2015
comment
но не следует ли AppKernel устанавливать экземпляр ядра? юнит-тесты проходят через одни и те же классы начальной загрузки.   -  person Rufinus    schedule 20.12.2015
comment
Да все верно. Я действительно не знаю, что происходит в вашем случае, я просто подумал, что эта страница может быть хорошим местом для начала...   -  person Radu Murzea    schedule 20.12.2015
comment
Можете ли вы показать код одного из неудавшихся тестовых классов?   -  person Dan Mironis    schedule 22.12.2015
comment
да, но это не поможет, как только я запрашиваю класс из контейнера, выдается ошибка. см. выше.   -  person Rufinus    schedule 22.12.2015
comment
Не могли бы вы также показать нам DoctrineTestCase класс? У меня ощущение, что что-то будет не так с настройкой ядра или получением контейнера.   -  person Dan Mironis    schedule 22.12.2015
comment
привет @Rufinus, чтобы воспроизвести ваш сценарий, если вы прокомментируете строку о fixLoad и логине пользователя, исключение будет hovenever throw?   -  person Matteo    schedule 23.12.2015
comment
Добавлен @DanMironis DoctrineTestCase.   -  person Rufinus    schedule 23.12.2015
comment
@Matteo попробовал, но исключение осталось прежним.   -  person Rufinus    schedule 23.12.2015
comment
Вы обновили свой phpunit? Помещение phpunit/phpunit в мой composer.json, а затем использование vendor/bin/phpunit вместо встроенного в систему phpunit помогло в моем случае (я не смог запустить набор тестов Symfony3 после обновления).   -  person Alain Tiemblo    schedule 23.12.2015
comment
@AlainTiemblo я всегда использую локальный phpunit (через композитор), текущая версия PHPUnit 5.1.3   -  person Rufinus    schedule 24.12.2015
comment
Не знаю, будет ли это полезно, но я наткнулся на эту страницу. , похоже, очень похожая проблема. Похоже, что static::$kernel может иногда хранить несогласованное значение, по словам репортера об ошибке.   -  person Dan Mironis    schedule 24.12.2015
comment
кажется, что jms/di-extra-bundle еще не готов для sf 2.8/3.0 github.com/ Шмиттджох/JMSDiExtraBundle/issues/224   -  person Matteo    schedule 24.12.2015
comment
@ Маттео, это не имеет ничего общего с DI-Extra. DI отлично работает в 2.8 (кроме предупреждений об устаревании)   -  person Rufinus    schedule 25.12.2015
comment
Вы не должны загружать ядро ​​в конструкторе тестового примера. Таким образом, он будет закрыт после выполнения первого теста (см. github.com/symfony/symfony/blob/master/src/Symfony/Bundle/). Вам лучше загрузить ядро ​​в методе setUp() тестового примера.   -  person xabbuh    schedule 25.12.2015
comment
@xabbuh да, это исправляет это в 8 из 10 случаев. я предполагаю, что остальные 2 являются крайними случаями и нуждаются в дальнейшей отладке. хочешь написать ответ, чтобы я мог начислить баллы?   -  person Rufinus    schedule 26.12.2015
comment
@xabbuh было бы хорошо, если бы вы могли оставить свой комментарий в качестве ответа. Руфинус, я надеюсь, вы будете ждать, пока он это сделает, потому что это определенно неправильно или несправедливо начислять баллы за плагиат за очевидную попытку уже одного пользователя.   -  person Trevor    schedule 26.12.2015
comment
@Rufinus Сделал это. Хотя я не уверен, что правильно понял, какие еще два случая вы имеете в виду. Не могли бы вы создать ответвление Symfony Standard Edition и внести изменения, необходимые для воспроизведения вашей проблемы?   -  person xabbuh    schedule 26.12.2015
comment
@xabbuh NotifcationTest работает, но в другом случае (глубоко в юнит-тесте рабочего процесса, управляемого событиями) у меня та же проблема. но я думаю, что это связано с этим событием или с созданием службы. мне нужно будет отладить это дальше, еще раз спасибо за указатель .... конечно, это имеет смысл, и я должен был заметить это, как только я нашел статью поваренной книги. ... часы отладки делают вас слепым, я думаю. Спасибо еще раз. Я наградил вас баллами, как и обещал.   -  person Rufinus    schedule 26.12.2015


Ответы (1)


Вы не должны загружать ядро ​​в конструкторе тестового примера. Таким образом, он будет закрыт после выполнения первого теста (см. https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php#).L186-L189). Вам лучше загрузить ядро ​​в методе setUp() тестового примера.

person xabbuh    schedule 26.12.2015
comment
пожалуйста, отредактируйте свой ответ в соответствии с вашим комментарием (у вас неработающая ссылка в вашем ответе) - person Sergio Ivanuzzo; 26.12.2015
comment
Спасибо, хаббух. Собственно наша проблема. Так просто загрузить ядро ​​не по методу setUpBeforeClass(), а по методу setUp(). - person Wulf; 08.08.2017