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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 请教:如何用postman调用本地虚拟机区块链接上的合约?
  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?
  • ¥15 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛