ZF3单元测试身份验证onBootstrap [英] ZF3 Unit test authentication onBootstrap

查看:104
本文介绍了ZF3单元测试身份验证onBootstrap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem getting a unit test to run for my IndexController class.

单元测试仅执行以下操作(灵感来自 zf3的单元测试教程):

The unit test just does the following (inspired from the unit-test tutorial of zf3):

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');
}

Module.php中,我具有一些功能来检查是否有用户登录,否则他将被重定向到login路由.

In the Module.php I've some functionality to check if there is a user logged in, else he will be redirected to a login route.

Module.php:

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.

The checkPermission method just checks if the user role and the matched route are in the acl storage. If this fails I will redirect a status code of 404.

问题:单元测试失败:声明响应代码"200"失败,实际状态代码为"302" 因此,单元测试从发生重定向的Module.php中的onBootstrap方法跳转到else情况.

Problem: The unit test fails: "Failed asserting response code "200", actual status code is "302" Therefore the unit test jumps into the else case from my onBootstrap method in the Module.php where the redirect happen.

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

I did the following setUp in the TestCase but it doesn't work:

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样式.

The code might differ a bit from Zend Framework 2 but If you have a simple working example in zf2 maybe I can transform it into zf3 style.

我不使用ZfcUser-只是zend-acl/zend-authentication之类的东西

I don't use ZfcUser - just the zend-acl / zend-authentication stuff

推荐答案

头痛几天后,我有了一个可行的解决方案.

After several days of headache I've got a working solution.

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

First I moved all the code within the onBootstrap to a Listener, because the phpunit mocks are generated after the zf bootstrapping and therefore are non existent in my unit tests.

关键是,这些服务是在我的可调用侦听器方法中生成的,该方法在zf完成引导之后调用. 然后,PHPUnit可以使用提供的模拟覆盖服务.

The key is, that the services are generated in my callable listener method, which is called after zf finished bootstrapping. Then PHPUnit can override the service with the provided 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想要的那样. 文档参考

Now my onBootstrap got really small, just like ZF wants it. documentation reference

Module.php

public function onBootstrap(MvcEvent $event)
{
    $authListener = new AuthenticationListener();
    $authListener->attach($event->getApplication()->getEventManager());
}

最后,我在单元测试中的模拟如下:

Finally my mocking in the unit test looks like this:

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);
}

这篇关于ZF3单元测试身份验证onBootstrap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆