2012-09-14 19 views
9

Ecco la mia situazione. Sto sviluppando un'applicazione Zend Framework 2. Sto usando il modulo Doctrine per comunicare con un database MySQL. Funziona bene nell'applicazione, posso caricare il gestore di entità dal localizzatore di servizio all'interno dei miei controller.Modulo Zend Framework 2 Doctrine 2 - Nessun localizzatore di servizio nei test dell'unità di controllo

Ma dentro mio test di unità del controller, il localizzatore di servizio non esiste e per questo tutti i test che si occupano con il database non riescono con il messaggio di errore come questo:

Fatal error: Call to a member function get() on a non-object in /Users/richardknop/Projects/myproject/module/Api/src/Api/Controller/UserController.php on line 19

ho ridotto il problema a questo metodo :

$this->getServiceLocator() 

Quale funziona nei miei controller ma restituisce NULL in unit test.

Questo è il mio application.config.php:

<?php 

return array(
    'modules' => array(
     'DoctrineModule', 
     'DoctrineORMModule', 
     'Api', 
    ), 
    'module_listener_options' => array(
     'config_glob_paths' => array(
      'config/autoload/{,*.}{global,local}.php', 
     ), 
     'module_paths' => array(
      './module', 
      './vendor', 
     ), 
    ), 
); 

Il mio file local.php con i dettagli di connessione al database:

<?php 

return array(
    'doctrine' => array(
     'connection' => array(
      'orm_default' => array(
       'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver', 
       'params' => array(
        'host'  => 'localhost', 
        'port'  => '3306', 
        'user'  => 'root', 
        'password' => 'root', 
        'dbname' => 'mydb', 
       ), 
      ), 
     ), 
    ), 
); 

Nel mio module.config.php ho:

'doctrine' => array(
    'driver' => array(
     __NAMESPACE__ . '_driver' => array(
      'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver', 
      'cache' => 'array', 
      'paths' => array(__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity') 
     ), 
     'orm_default' => array(
      'drivers' => array(
       __NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver' 
      ), 
     ), 
    ), 
), 

E nei miei controller ho questo metodo per ottenere il gestore di entità:

private $_em; 

private function _getEntityManager() 
{ 
    if (null === $this->_em) { 
     $this->_em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default'); 
    } 
    return $this->_em; 
} 

Ora la mia unità prova. Ecco il file di bootstrap:

<?php 

chdir(dirname(__DIR__)); 
include __DIR__ . '/../init_autoloader.php'; 
return Zend\Mvc\Application::init(include 'config/application.config.php'); 

E metodo di impostazione dei miei test del controller appare come:

public function setUp() 
{ 
    $this->_controller = new UserTokenController; 
    $this->_request = new Request; 
    $this->_routeMatch = new RouteMatch(array('controller' => 'user')); 
    $this->_event = new MvcEvent(); 
    $this->_event->setRouteMatch($this->_routeMatch); 
    $this->_controller->setEvent($this->_event); 
} 

Un test di unità di controllo esempio appare quindi come:

public function testGetListHttpStatusCode() 
{ 
    $response = $this->_controller->dispatch($this->_request); 
    $this->assertEquals(405, $response->getStatusCode()); 
} 

Tutti i test che sono non si sta connettendo al database. I test in cui mi sto usando gestore di entità non riescono però con questo errore:

Fatal error: Call to a member function get() on a non-object in /Users/richardknop/Projects/myproject/module/Api/src/Api/Controller/UserController.php on line 19

Questa è la riga 19:

$this->_em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default'); 

E la ragione è in mancanza è che $this->getServiceLocator() rendimenti NULL.

Qualche idea su come risolvere questo problema?

risposta

6

Dont' fare questo ins tuo bootstrap.php

return Zend\Mvc\Application::init(include 'config/application.config.php');` in your 

, ma qualcosa di simile:

chdir('/path/to/application/root'); 

// if you're using composer to install zf2 
include_once 'vendor/autoload.php'; 
// if not using composer initialize your custom autoloading here 

$configuration = include('config/application.config.php'); 
$serviceManager = new ServiceManager(new ServiceManagerConfig(
    isset($configuration['service_manager']) ? $configuration['service_manager'] : array() 
)); 
$serviceManager->setService('ApplicationConfig', $configuration); 
$serviceManager->setFactory('ServiceListener', 'Zend\Mvc\Service\ServiceListenerFactory'); 

$moduleManager = $serviceManager->get('ModuleManager'); 
$moduleManager->loadModules(); 
$serviceManager->setAllowOverride(true); 

$application = $serviceManager->get('Application'); 
$event = new MvcEvent(); 
$event->setTarget($application); 
$event->setApplication($application) 
    ->setRequest($application->getRequest()) 
    ->setResponse($application->getResponse()) 
    ->setRouter($serviceManager->get('Router')); 

si potrebbe quindi creare metodi statici nel test-case per impostare e ottenere l'evento. ..

namespace My; 

class TestCase extends \Some\Basic\TestCase 
{ 
    protected static $_mvcEvent; 

    public static function setMvcEvent(MvcEvent $e) { 

     self::$_mvcEvent = $e; 
    } 

    public static function getMvcEvent() { 

     return self::$_mvcEvent; 
    } 
} 

... e iniettare dal file bootstrap.php

My\TestCase::setMvcEvent($event); 

e nel vostro metodo di configurazione del test semplicemente fare qualcosa di simile

$this->_controller = new UserTokenController; 
$this->_controller->setEvent(self::getMvcEvent()); 
$this->_controller->setServiceLocator(
    self::getMvcEvent()->getApplication()->getServiceManager() 
); 

anche iniettare richiesta etc da evento-> applicazione nel controller qui ...

+0

Dopo tutto, ho usato un approccio leggermente diverso (ma l'idea principale è la stessa, ho solo messo più logica dentro di me Bootstrap.php per phpunit). Ma anche il tuo funziona. –

+0

anche il mio fa molto di più, lo ha semplicemente ridotto ai requisiti di base –

+0

Ciao Andreas. Sto anche usando ZF2 + Doctrine2 e sto seguendo il tuo metodo. Mentre ServiceLocator è impostato, sembra che l'evento non venga propagato ai plug-in Controller: il router, per esempio, è impostato nel serviceLocator ma non nel plugin redirect(). Qualche idea su come impostare questo? – Ross

0

Estendi semplicemente il controller da \ Zend \ Test \ PHPUnit \ Controller \ AbstractHttpControllerTestCase

È localizzatore di servizi di init e svolge molti altri compiti di Controller. Inoltre, diventano disponibili asserzioni di controller, richieste di risposta, affermazioni CSS ecc. Dettagli con esempi guardate qui http://framework.zend.com/manual/2.1/en/modules/zend.test.phpunit.html

Problemi correlati