unit-testingmockingzend-framework3view-helperszend-servicemanager

Mock view helper in Zend Framework 3 in PHPUnit test


I want to test a specific controller action in Zend Framework 3. Because I use ZfcUser (https://github.com/ZF-Commons/ZfcUser) and Bjyauthorize (https://github.com/bjyoungblood/BjyAuthorize) I need to mock some view helpers. For example I need to mock isAllowed view helper and let it return true always:

class MyTest extends AbstractControllerTestCase
{
    public function setUp()
    {
        $this->setApplicationConfig(include 'config/application.config.php');
        $bootstrap      = \Zend\Mvc\Application::init(include 'config/application.config.php');
        $serviceManager = $bootstrap->getServiceManager();

        $viewHelperManager = $serviceManager->get('ViewHelperManager');

        $mock = $this->getMockBuilder(IsAllowed::class)->disableOriginalConstructor()->getMock();
        $mock->expects($this->any())->method('__invoke')->willReturn(true);

        $viewHelperManager->setService('isAllowed', $mock);

        $this->getApplication()->getServiceManager()->setAllowOverride(true);
        $this->getApplication()->getServiceManager()->setService('ViewHelperManager', $viewHelperManager);
    }

    public function testViewAction()
    {
        $this->dispatch('/myuri');
        $resp = $this->getResponse();
        $this->assertResponseStatusCode(200);
        #$this->assertModuleName('MyModule');
        #$this->assertMatchedRouteName('mymodule/view');
    }
}

In my view.phtml (which will be rendered by opening/dispatching /myuri uri) I call the view helper $this->isAllowed('my-resource').

But I got response code 500 with failing exception when executing testViewAction():

Exceptions raised:
Exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'A plugin by the name "isAllowed" was not found in the plugin manager Zend\View\HelperPluginManager' in ../vendor/zendframework/zend-servicemanager/src/AbstractPluginManager.php:131

How can I inject my isAllowed mock to the view helper manager in a way, that let the test case (testViewAction / $this->dispatch()) pass.


Solution

  • As stated in the previous answer already, we need to override the ViewHelper within the ViewHelperManager in the application object. The following code shows how this could be achieved:

    public function setUp()
    {
        $this->setApplicationConfig(include 'config/application.config.php');
        $bootstrap = \Zend\Mvc\Application::init(include 'config/application.config.php');
        $serviceManager = $bootstrap->getServiceManager();
    
        // mock isAllowed View Helper of Bjyauthorize
        $mock = $this->getMockBuilder(IsAllowed::class)->disableOriginalConstructor()->getMock();
        $mock->expects($this->any())->method('__invoke')->willReturn(true);
    
        // inject the mock into the ViewHelperManager of the application
        $this->getApplication()->getServiceManager()->get('ViewHelperManager')->setAllowOverride(true);
        $this->getApplication()->getServiceManager()->get('ViewHelperManager')->setService('isAllowed', $mock);
    }