Php ZF3单元测试自举验证

Php ZF3单元测试自举验证,php,authentication,phpunit,zend-framework3,Php,Authentication,Phpunit,Zend Framework3,我在为我的IndexController类运行单元测试时遇到问题 单元测试仅执行以下操作(灵感来自: IndexControllerTest.php: public function testIndexActionCanBeAccessed() { $this->dispatch('/', 'GET'); $this->assertResponseStatusCode(200); $this->assertModuleName('main');

我在为我的
IndexController
类运行单元测试时遇到问题

单元测试仅执行以下操作(灵感来自:

IndexControllerTest.php

public function testIndexActionCanBeAccessed()
{
    $this->dispatch('/', 'GET');
    $this->assertResponseStatusCode(200);
    $this->assertModuleName('main');
    $this->assertControllerName(IndexController::class); // as specified in router's controller name alias
    $this->assertControllerClass('IndexController');
    $this->assertMatchedRouteName('main');
}
public function onBootstrap(MvcEvent $mvcEvent)
{
    /** @var AuthService $authService */
    $authService = $mvcEvent->getApplication()->getServiceManager()->get(AuthService::class);
    $this->auth = $authService->getAuth(); // returns the Zend AuthenticationService object

    // store user and role in global viewmodel
    if ($this->auth->hasIdentity()) {
        $curUser = $this->auth->getIdentity();
        $mvcEvent->getViewModel()->setVariable('curUser', $curUser['system_name']);
        $mvcEvent->getViewModel()->setVariable('role', $curUser['role']);
        $mvcEvent->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, [$this, 'checkPermission']);
    } else {
        $mvcEvent->getApplication()->getEventManager()->attach(MvcEvent::EVENT_DISPATCH, [$this, 'authRedirect'], 1000);
    }
}
Module.php
中,我有一些功能来检查是否有用户登录,否则他将被重定向到
登录路径

Module.php

public function testIndexActionCanBeAccessed()
{
    $this->dispatch('/', 'GET');
    $this->assertResponseStatusCode(200);
    $this->assertModuleName('main');
    $this->assertControllerName(IndexController::class); // as specified in router's controller name alias
    $this->assertControllerClass('IndexController');
    $this->assertMatchedRouteName('main');
}
public function onBootstrap(MvcEvent $mvcEvent)
{
    /** @var AuthService $authService */
    $authService = $mvcEvent->getApplication()->getServiceManager()->get(AuthService::class);
    $this->auth = $authService->getAuth(); // returns the Zend AuthenticationService object

    // store user and role in global viewmodel
    if ($this->auth->hasIdentity()) {
        $curUser = $this->auth->getIdentity();
        $mvcEvent->getViewModel()->setVariable('curUser', $curUser['system_name']);
        $mvcEvent->getViewModel()->setVariable('role', $curUser['role']);
        $mvcEvent->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, [$this, 'checkPermission']);
    } else {
        $mvcEvent->getApplication()->getEventManager()->attach(MvcEvent::EVENT_DISPATCH, [$this, 'authRedirect'], 1000);
    }
}
checkPermission
方法只检查用户角色和匹配的路由是否在acl存储中。 如果失败,我将重定向404状态代码

问题:单元测试失败:“断言响应代码“200”失败,实际状态代码为“302” 因此,单元测试从发生重定向的
Module.php
中我的
onBootstrap
方法跳转到else案例中

我在TestCase中执行了以下
设置
,但它不起作用:

public function setUp()
{
    // override default configuration values
    $configOverrides = [];

    $this->setApplicationConfig(ArrayUtils::merge(
        include __DIR__ . '/../../../../config/application.config.php',
        $configOverrides
    ));

    $user = new Employee();
    $user->id = 1;
    $user->system_name = 'admin';
    $user->role = 'Admin';

    $this->authService = $this->prophesize(AuthService::class);
    $auth = $this->prophesize(AuthenticationService::class);
    $auth->hasIdentity()->willReturn(true);
    $auth->getIdentity()->willReturn($user);

    $this->authService->getAuth()->willReturn($auth->reveal());

    $this->getApplicationServiceLocator()->setAllowOverride(true);
    $this->getApplicationServiceLocator()->setService(AuthService::class, $this->authService->reveal());
    $this->getApplicationServiceLocator()->setAllowOverride(false);

    parent::setUp();
}
非常感谢您的提示

代码可能与Zend Framework 2稍有不同,但如果您在zf2中有一个简单的工作示例,也许我可以将其转换为zf3样式


我不使用ZfcUser-只是zend acl/zend身份验证的东西

在头痛了几天之后,我找到了一个有效的解决方案

首先,我将
onBootstrap
中的所有代码移动到侦听器中,因为phpunit mock是在zf引导之后生成的,因此在我的单元测试中不存在

关键是,服务是在我的可调用侦听器方法中生成的,该方法在zf完成引导后调用。 然后PHPUnit可以用提供的mock覆盖服务

AuthenticationListener

class AuthenticationListener implements ListenerAggregateInterface
{
use ListenerAggregateTrait;

/**
 * @var AuthenticationService
 */
private $auth;

/**
 * @var Acl
 */
private $acl;

/**
 * Attach one or more listeners
 *
 * Implementors may add an optional $priority argument; the EventManager
 * implementation will pass this to the aggregate.
 *
 * @param EventManagerInterface $events
 * @param int $priority
 *
 * @return void
 */
public function attach(EventManagerInterface $events, $priority = 1)
{
    $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, [$this, 'checkAuthentication']);
}

/**
 * @param MvcEvent $event
 */
public function checkAuthentication($event)
{
    $this->auth = $event->getApplication()->getServiceManager()->get(AuthenticationService::class);
    $aclService = $event->getApplication()->getServiceManager()->get(AclService::class);
    $this->acl = $aclService->init();

    $event->getViewModel()->setVariable('acl', $this->acl);
    if ($this->auth->hasIdentity()) {
        $this->checkPermission($event);
    } else {
        $this->authRedirect($event);
    }
}

// checkPermission & authRedirect method
}
现在我的
onBootstrap
变得非常小,就像ZF想要的那样

Module.php

public function onBootstrap(MvcEvent $event)
{
    $authListener = new AuthenticationListener();
    $authListener->attach($event->getApplication()->getEventManager());
}
最后,我在单元测试中的模拟如下所示:

IndexControllerTest

private function authMock()
{
    $mockAuth = $this->getMockBuilder(AuthenticationService::class)->disableOriginalConstructor()->getMock();
    $mockAuth->expects($this->any())->method('hasIdentity')->willReturn(true);
    $mockAuth->expects($this->any())->method('getIdentity')->willReturn(['id' => 1, 'systemName' => 'admin', 'role' => 'Admin']);

    $this->getApplicationServiceLocator()->setAllowOverride(true);
    $this->getApplicationServiceLocator()->setService(AuthenticationService::class, $mockAuth);
    $this->getApplicationServiceLocator()->setAllowOverride(false);
}

我已尝试了您的解决方案,但出现错误
Zend\ServiceManager\Exception\ServiceNotFoundException:Zend\ServiceManager\ServiceManager::get无法获取或创建Zend\Authentication\AuthenticationService的实例