douyan1882 2016-05-23 20:06
浏览 47
已采纳

getServiceLocator在PHPUnittests下返回Null

I'm trying to test a simple controller that authenticates a user using the LdapAdapter and using the 'ldap' array from the configuration of the Application, but phpunit is returning the following error:

Fatal error: Uncaught Error: Call to a member function get() on null in /var/www/html/app/module/Auth/src/Auth/Controller/AuthController.php:53
Stack trace:
#0 /var/www/html/app/module/Auth/test/AuthTest/Controller/AuthControllerTest.php(37): Auth\Controller\AuthController->authenticate('myuser', 'mypassword')
#1 [internal function]: AuthTest\Controller\AlbumControllerTest->testLoginAction()
#2 /var/www/html/vendor/phpunit/phpunit/src/Framework/TestCase.php(863): ReflectionMethod->invokeArgs(Object(AuthTest\Controller\AlbumControllerTest), Array)
#3 /var/www/html/vendor/phpunit/phpunit/src/Framework/TestCase.php(741): PHPUnit_Framework_TestCase->runTest()
#4 /var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php(608): PHPUnit_Framework_TestCase->runBare()
#5 /var/www/html/vendor/phpunit/phpunit/src/Framework/TestCase.php(697): PHPUnit_Framework_TestResult->run(Object(AuthTest\Controller\AlbumControllerTest))
#6 /var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php(733): PHPUnit_Framework_TestCase- in /var/www/html/app/module/Auth/src/Auth/Controller/AuthController.php on line 53

My Controller is the following:

<?php

namespace Auth\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\Authentication\Adapter\Ldap as AuthAdapter;
use Zend\Authentication\AuthenticationService;
use Zend\Authentication\Result;
use Auth\Form\AuthForm;
use Auth\Model\Auth;


class AuthController extends AbstractActionController
{

    public function loginAction()
    {

        $form = new AuthForm();

        $request = $this->getRequest();
        if ($request->isPost()) {
            $auth = new Auth();

            $form->setInputFilter($auth->getInputFilter());
            $form->setData($request->getPost());

            if ($form->isValid()){
                $auth->exchangeArray($form->getData());

                $values = $form->getData();

                $result = $this->authenticate($values['username'], $values['password']);

                switch($result->getCode()) {

                    case Result::SUCCESS:
                        return $this->redirect()->toRoute('home');
                        break;

                    case Result::FAILURE:
                        break;
                    }
                }

            }
        return array('form' => $form);

        }

    public function authenticate($username, $password){

        $options = $this->getServiceLocator()->get('Config');

        $authAdapter = new AuthAdapter($options['ldap'],
            'username',
            'password');

        $authAdapter
            ->setIdentity($username)
            ->setCredential($password);

        $auth = new AuthenticationService();

        $result = $auth->authenticate($authAdapter);

        return $result;
    }

    private function debug($var){
        echo '<pre>';
        var_dump($var);
        echo '</pre>';
        exit();
    }
}

The TestCase:

namespace AuthTest\Controller;

use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
use Zend\Authentication\AuthenticationService;
use Auth\Controller\AuthController;


class AuthControllerTest extends AbstractHttpControllerTestCase
{
    protected $traceError = true;

    public function setUp()
    {
        $this->setApplicationConfig(
            include '/var/www/html/app/config/application.config.php'
        );
        parent::setUp();
    }

    public function testLoginAction()
    {
        #Basic Access to the page
        $this->dispatch('/login');
        $this->assertResponseStatusCode(200);

        $data = array(
            'identity' => 'myuser',
            'credential' => 'mypassword',
        );

        $auth = new AuthController();
        $auth->authenticate($data['identity'], $data['credential']);

        $identity = new AuthenticationService();
        $this->assertEquals($data['identity'], $identity->getIdentity());
    }
}

PHPUnittest's BootStrap:

<?php

namespace AuthTest;

use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use RuntimeException;

error_reporting(E_ALL | E_STRICT);
chdir(__DIR__);

/**
 * Test bootstrap, for setting up autoloading
 */
class Bootstrap
{
    protected static $serviceManager;

    public static function init()
    {
        $zf2ModulePaths = array(dirname(dirname(__DIR__)));
        if (($path = static::findParentPath('vendor'))) {
            $zf2ModulePaths[] = $path;
        }
        if (($path = static::findParentPath('module')) !== $zf2ModulePaths[0]) {
            $zf2ModulePaths[] = $path;
        }

        static::initAutoloader();

        // use ModuleManager to load this module and it's dependencies
        $config = array(
            'module_listener_options' => array(
                'module_paths' => $zf2ModulePaths,
            ),
            'modules' => array(
                'Auth'
            )
        );

        $serviceManager = new ServiceManager(new ServiceManagerConfig());
        $serviceManager->setService('ApplicationConfig', $config);
        $serviceManager->get('ModuleManager')->loadModules();
        static::$serviceManager = $serviceManager;
    }

    public static function chroot()
    {
        $rootPath = dirname(static::findParentPath('module'));
        chdir($rootPath);
    }

    public static function getServiceManager()
    {
        return static::$serviceManager;
    }

    protected static function initAutoloader()
    {
        $vendorPath = static::findParentPath('vendor');

        if (file_exists($vendorPath.'/autoload.php')) {
            include $vendorPath.'/autoload.php';
        }

        if (! class_exists('Zend\Loader\AutoloaderFactory')) {
            throw new RuntimeException(
                'Unable to load ZF2. Run `php composer.phar install`'
            );
        }

        AutoloaderFactory::factory(array(
            'Zend\Loader\StandardAutoloader' => array(
                'autoregister_zf' => true,
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
                ),
            ),
        ));
    }

    protected static function findParentPath($path)
    {
        $dir = __DIR__;
        $previousDir = '.';
        while (!is_dir($dir . '/' . $path)) {
            $dir = dirname($dir);
            if ($previousDir === $dir) {
                return false;
            }
            $previousDir = $dir;
        }
        return $dir . '/' . $path;
    }
}

Bootstrap::init();
Bootstrap::chroot();

In the functional tests it works as expected, but on php unittests the error occurs in the line 53 '$options = $this->getServiceLocator()->get('Config');'.

So, how can use or set ServiceLocator to work with phpunittests?

  • 写回答

1条回答 默认 最新

  • dongzhiyan5693 2016-06-07 20:00
    关注

    After so much struggling on this doubt and other tests which a controller that uses an ServiceLocator, I figure that the correct way to test a controllers Action is to Mock the object or/and his methods.

    I don't feel totally comfortable with this solution, but for now, this is what it is.

    An other feel is that mocking an behaviour of the code is something like that breaks the DRY principle: instead of use the real code I just create a mock that half behaves like it :S

    Anyway, the following code does the job for me:

        $authControllerMock = $this->getMockBuilder('Auth\Controller\AuthController')
            ->disableOriginalConstructor()
            ->getMock();
    
        $authControllerMock->expects($this->any())
            ->method('authenticate')
            ->will($this->returnValue(true);
    
        $serviceManager = $this->getApplicationServiceLocator();
        $serviceManager->setAllowOverride(true);
        $serviceManager->setService('Auth\Controller\Auth', $authControllerMock);
    
        $this->dispatch('/usermgr');
    
        self::assertMatchedRouteName('usermgr');
        self::assertControllerClass('AuthController');
        self::assertControllerName('auth\controller\auth');
        self::assertResponseStatusCode('200');
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度