2015-12-19 15 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

相關問題