2015-12-19 55 views
10

我使用Twig_Environment来呈现要发送的html邮件。我有一个NotificationService类被其他服务用来发送这些邮件。服务类中的Twig_Environment仅在Symfony 2.8中进行单元测试时才导致DIC RuntimeExtension

在正常使用的情况,一切正常,但由于更新到2.8的单元测试失败: Symfony\Component\DependencyInjection\Exception\RuntimeException: You have requested a synthetic service ("kernel"). The DIC does not know how to construct this service

我调试的堆栈跟踪,问题似乎是Twig_Environment(使用中注入kernelfile_locator

/** 
* 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] 
} 

EDIT2:

/** 
* 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); 
    } 
} 

EDIT3: 歌厅内核似乎已经过去有时会发生变化。 看到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(); 
} 

到:

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

    self::bootKernel(); 

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

,但不幸的是,当测试使用Twig_Env它不固定的RuntimeException。

+1

也许[本页](http://symfony.com/doc/2.8/components/dependency_injection/synthetic_services.html)会有所帮助。 –

+0

但shoudnt AppKernel设置内核实例? unittests通过相同的引导类。 – Rufinus

+0

是的,没错。我真的不知道你的情况是怎么回事,我只是认为这个页面可能是一个很好的开始...... –

回答

8

您不应该在测试用例的构造函数中引导内核。这样它将在第一次测试执行后关闭(请参阅https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php#L186-L189)。您应该在测试案例的setUp()方法中引导内核。

+0

请根据您的评论编辑您的答案(您在答案中已断开链接) –

+0

感谢您的注意 – xabbuh

+0

谢谢xabbuh。确实是我们的问题。非常简单,只需在'setUpBeforeClass()'中引导内核,而在'setUp()'方法中引导内核。 – Wulf

相关问题