doupijin0397
2012-12-25 16:20
浏览 35
已采纳

Zend Framework 2 - 如何对自己的会话服务进行单元测试?

I have a problem with unit testing of my own SessionManager service. I don't have errors in unit tests but session isn't created in database and i can't write to storage. Here is my code:

SessionManagerFactory:

namespace Admin\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Session\SaveHandler\DbTableGatewayOptions as SessionDbSavehandlerOptions;
use Zend\Session\SaveHandler\DbTableGateway;
use Zend\Session\Config\SessionConfig;
use Zend\Session\SessionManager;
use Zend\Db\TableGateway\TableGateway;

class SessionManagerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        return $this;
    }

    public function setUp(ServiceManager $serviceManager)
    {
        $sessionOptions = new SessionDbSavehandlerOptions();
        $sessionOptions->setDataColumn('data')
                       ->setIdColumn('id')
                       ->setModifiedColumn('modified')
                       ->setLifetimeColumn('lifetime')
                       ->setNameColumn('name');
        $dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
        $sessionTableGateway = new TableGateway('zf2_sessions', $dbAdapter);
        $sessionGateway = new DbTableGateway($sessionTableGateway, $sessionOptions);
        $config = $serviceManager->get('Configuration');
        $sessionConfig = new SessionConfig();
        $sessionConfig->setOptions($config['session']);
        $sessionManager = new SessionManager($sessionConfig);
        $sessionManager->setSaveHandler($sessionGateway);

        return $sessionManager;
    }
}

GetServiceConfig() method from Module.php in Admin namespace:

public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Zend\Authentication\Storage\Session' => function($sm) {
                    return new StorageSession();
                },
                'AuthService' => function($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $authAdapter = new AuthAdapter($dbAdapter, 'zf2_users', 'email', 'password');

                    $authService = new AuthenticationService();
                    $authService->setAdapter($authAdapter);
                    $authService->setStorage($sm->get('Zend\Authentication\Storage\Session'));

                    return $authService;
                },
                'SessionManager' => function($serviceManager){
                    $sessionManager = new SessionManagerFactory();
                    return $sessionManager->setUp($serviceManager);
                }
            )
        );
    }

And setUp() mehod from unit test file:

protected function setUp()
    {
        $bootstrap             = \Zend\Mvc\Application::init(include 'config/app.config.php');
        $this->controller      = new SignController;
        $this->request         = new Request;
        $this->routeMatch      = new RouteMatch(array('controller' => 'sign'));
        $this->event           = $bootstrap->getMvcEvent();

        // Below line should start session and storage it in Database. 
        $bootstrap->getServiceManager()->get('SessionManager')->start();
        // And this line should add test variable to default namespace of session, but doesn't - blow line is only for quick test. I will write method for test write to storage.
        Container::getDefaultManager()->test = 12;

        $this->event->setRouteMatch($this->routeMatch);
        $this->controller->setEvent($this->event);
        $this->controller->setEventManager($bootstrap->getEventManager());
        $this->controller->setServiceLocator($bootstrap->getServiceManager());
    }

How to test this service and why session aren't created?

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doushi1960 2013-06-13 05:10
    已采纳

    I think you've misunderstood the Factory pattern. Your factory should look like the following. The separate setUp method is NEVER called anywhere as far as I can tell. You don't call it manually anywhere.

    class SessionManagerFactory implements FactoryInterface
    {
        public function createService(ServiceLocatorInterface $serviceLocator)
        {
            $sessionOptions = new SessionDbSavehandlerOptions();
            $sessionOptions->setDataColumn('data')
                           ->setIdColumn('id')
                           ->setModifiedColumn('modified')
                           ->setLifetimeColumn('lifetime')
                           ->setNameColumn('name');
            $dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
            $sessionTableGateway = new TableGateway('zf2_sessions', $dbAdapter);
            $sessionGateway = new DbTableGateway($sessionTableGateway, $sessionOptions);
            $config = $serviceManager->get('Configuration');
            $sessionConfig = new SessionConfig();
            $sessionConfig->setOptions($config['session']);
            $sessionManager = new SessionManager($sessionConfig);
            $sessionManager->setSaveHandler($sessionGateway);
    
            return $sessionManager;
    
        }
    
    }
    

    All the following code works for me. I think you are missing some other things but the above should fix it. Look for the SEE ME comments below. Also, add an onBootstrap method to your Module.php like I have below and make sure to call the $sessionManager = $serviceManager->get( 'SessionManager' ); in your case so that your SessionFactory is actually called. You already call it in your setup() function in the unit test but if you call it in the module you won't have to manually call it yourself.

    In application.config I have this

    'session' => array(
            'name'                => 'PHPCUSTOM_SESSID',
            'cookie_lifetime'     => 300, //1209600, //the time cookies will live on user browser
            'remember_me_seconds' => 300, //1209600 //the time session will live on server
            'gc_maxlifetime'      => 300
        )
    'db' => array(
            'driver' => 'Pdo_Sqlite',
            'database' => '/tmp/testapplication.db'
        ),
    

    My session factory is very similar but I have one extra line of code. Look for the comment.

    use Zend\ServiceManager\FactoryInterface,
        Zend\ServiceManager\ServiceLocatorInterface,
        Zend\Session\SessionManager,
        Zend\Session\Config\SessionConfig,
        Zend\Session\SaveHandler\DbTableGateway as SaveHandler,
        Zend\Session\SaveHandler\DbTableGatewayOptions as SaveHandlerOptions,
        Zend\Db\Adapter\Adapter,
        Zend\Db\TableGateway\TableGateway;
    
    class SessionFactory
        implements FactoryInterface
    {
    
        public function createService( ServiceLocatorInterface $sm )
        {
            $config = $sm->has( 'Config' ) ? $sm->get( 'Config' ) : array( );
            $config = isset( $config[ 'session' ] ) ? $config[ 'session' ] : array( );
            $sessionConfig = new SessionConfig();
            $sessionConfig->setOptions( $config );
    
            $dbAdapter = $sm->get( '\Zend\Db\Adapter\Adapter' );
    
            $sessionTableGateway = new TableGateway( 'sessions', $dbAdapter );
            $saveHandler = new SaveHandler( $sessionTableGateway, new SaveHandlerOptions() );
    
            $manager = new SessionManager();
            /******************************************/
            /* SEE ME : I DON'T SEE THE LINE BELOW IN YOUR FACTORY. It probably doesn't matter though. 
            /******************************************/
    
            $manager->setConfig( $sessionConfig );  
            $manager->setSaveHandler( $saveHandler );
    
            return $manager;
        }
    

    In one of my modules I have the following

    public function onBootstrap( EventInterface $e )
        {
    
            // You may not need to do this if you're doing it elsewhere in your
            // application
            /* @var $eventManager \Zend\EventManager\EventManager  */
            /* @var $e \Zend\Mvc\MvcEvent */
            $eventManager = $e->getApplication()->getEventManager();
    
            $serviceManager = $e->getApplication()->getServiceManager();
    
            $moduleRouteListener = new ModuleRouteListener();
            $moduleRouteListener->attach( $eventManager );
    
            try
            {
                //try to connect to the database and start the session
                /* @var $sessionManager SessionManager */
                $sessionManager = $serviceManager->get( 'Session' );
    
                /******************************************/
                /* SEE ME : Make sure to start the session
                /******************************************/
                $sessionManager->start();
            }
            catch( \Exception $exception )
            {
                //if we couldn't connect to the session then we trigger the
                //error event
                $e->setError( Application::ERROR_EXCEPTION )
                    ->setParam( 'exception', $exception );
                $eventManager->trigger( MvcEvent::EVENT_DISPATCH_ERROR, $e );
            }
        }
    
    }
    

    This is my getServiceConfigMethod

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Session' => '\My\Mvc\Service\SessionFactory',
                '\Zend\Db\Adapter\Adapter' => '\Zend\Db\Adapter\AdapterServiceFactory'
            )
        );
    }
    

    I'm using sqllite at the moment so the table has to exist in your sqllite file already.

    If you're using mysql, it should exist in that database too and you should change your db settings in the application.config.php file.

    已采纳该答案
    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题