2013-01-16 54 views
8

我在嘗試單元測試使用ZfcUser進行身份驗證的操作時遇到了問題。我需要一些方法來模擬ZfcUser控制器插件,但我不太確定如何做到這一點。我已經成功地爲表和模型生成了一些單元測試,但是控制器需要大量的注入對象並導致問題。有誰知道如何設置ZfcUser mocks來成功地測試控制器?簡單的ZF2單元測試使用ZfcUser的控制器

這裏是我的測試(從ZF2教程複製):

<?php 
namespace SmsTest\Controller; 

use SmsTest\Bootstrap; 
use Sms\Controller\SmsController; 
use Zend\Http\Request; 
use Zend\Http\Response; 
use Zend\Mvc\MvcEvent; 
use Zend\Mvc\Router\RouteMatch; 
use Zend\Mvc\Router\Http\TreeRouteStack as HttpRouter; 
use PHPUnit_Framework_TestCase; 

class SmsControllerTest extends PHPUnit_Framework_TestCase 
{ 
    protected $controller; 
    protected $request; 
    protected $response; 
    protected $routeMatch; 
    protected $event; 

    protected function setUp() 
    { 

     $serviceManager = Bootstrap::getServiceManager(); 

     $this->controller = new SmsController(); 
     $this->request = new Request(); 
     $this->routeMatch = new RouteMatch(array('controller' => 'index')); 
     $this->event  = new MvcEvent(); 
     $config = $serviceManager->get('Config'); 
     $routerConfig = isset($config['router']) ? $config['router'] : array(); 
     $router = HttpRouter::factory($routerConfig); 
     $this->event->setRouter($router); 
     $this->event->setRouteMatch($this->routeMatch); 
     $this->controller->setEvent($this->event); 
     $this->controller->setServiceLocator($serviceManager); 
    } 


    /* Test all actions can be accessed */ 

    public function testIndexActionCanBeAccessed() 
    { 
     $this->routeMatch->setParam('action', 'index'); 

     $result = $this->controller->dispatch($this->request); 
     $response = $this->controller->getResponse(); 

     $this->assertEquals(200, $response->getStatusCode()); 
    } 
} 

我試着在設置方法如下:

$mockAuth = $this->getMock('ZfcUser\Entity\UserInterface'); 


    $authMock = $this->getMock('Zend\Authentication\AuthenticationService'); 
    $authMock->expects($this->any()) 
     ->method('hasIdentity') 
     ->will($this->returnValue(true)); 

    $authMock->expects($this->any()) 
     ->method('getIdentity') 
     ->will($this->returnValue(array('user_id' => 1))); 

但我不知道如何在這個注入到控制器實例。

允許假裝我的索引行動碼是隻是如下:

public function indexAction() { 
    //Check if logged in 
    if (!$this->zfcUserAuthentication()->hasIdentity()) { 
     return $this->redirect()->toRoute('zfcuser/login'); 
    } 

    return new ViewModel(array(
     'success' => true, 
    )); 
} 

試驗結果:

1) SmsTest\Controller\SmsControllerTest::testIndexActionCanBeAccessed 
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for zfcUserAuthentication 

/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:450 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php:110 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/PluginManager.php:90 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:276 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:291 
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:974 
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:974 
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:158 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php:87 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:208 
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:108 
/var/www/soap-app.localhost/Zend/module/Sms/test/SmsTest/Controller/SmsControllerTest.php:57 

這導致該異常是所述控制器的線:如果(!$this->zfcUserAuthentication()->hasIdentity()) { 即線涉及SmsController中的第974行。

很明顯,我沒有訪問ZfcUserAuthentication服務,所以問題是,如何嘲笑ZfcUserAuthentication服務並將其注入到我的控制器?

要繼續主題,我將如何去嘲笑登錄的用戶以成功測試我的操作是否符合規範?

回答

10

ZfcUser文檔建議這是一個插件,因此您需要將其注入控制器。

您將需要修改你的類名拿起ZfcUser類

你的嘲笑也將需要addapted作爲getIdenty返回不同的對象。

以下爲我工作 - 插入您的phpunit setUp()方法。

$serviceManager = Bootstrap::getServiceManager(); 
$this->controller = new RegisterController(); 
$this->request = new Request(); 
$this->routeMatch = new RouteMatch(array('controller' => 'add')); 
$this->event  = new MvcEvent(); 
$config = $serviceManager->get('Config'); 
$routerConfig = isset($config['router']) ? $config['router'] : array(); 
$router = HttpRouter::factory($routerConfig); 
$this->event->setRouter($router); 
$this->event->setRouteMatch($this->routeMatch); 
$this->controller->setEvent($this->event); 
$this->controller->setServiceLocator($serviceManager); 
$mockAuth = $this->getMock('ZfcUser\Entity\UserInterface'); 

$ZfcUserMock = $this->getMock('ZfcUser\Entity\User'); 

$ZfcUserMock->expects($this->any()) 
      ->method('getId') 
      ->will($this->returnValue('1')); 

$authMock = $this->getMock('ZfcUser\Controller\Plugin\ZfcUserAuthentication'); 

$authMock->expects($this->any()) 
     ->method('hasIdentity') 
      -> will($this->returnValue(true)); 

$authMock->expects($this->any()) 
     ->method('getIdentity') 
     ->will($this->returnValue($ZfcUserMock)); 

$this->controller->getPluginManager() 
    ->setService('zfcUserAuthentication', $authMock); 

有可能是一個更簡單的方法,會歡迎其他的想法。

0

這就是我做到的。

<?php 

namespace IssueTest\Controller; 

use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase; 

class IssueControllerTest extends AbstractHttpControllerTestCase 
{ 
    protected $serviceManager; 

    public function setUp() 
    { 
     $this->setApplicationConfig(
      include '/media/policybubble/config/application.config.php' 
     ); 
     parent::setUp(); 
     $ZfcUserMock = $this->getMock('ZfcUser\Entity\User'); 
     $ZfcUserMock->expects($this->any()) 
      ->method('getId') 
      ->will($this->returnValue('1')); 
     $authMock = $this->getMock(
      'ZfcUser\Controller\Plugin\ZfcUserAuthentication' 
     ); 
     $authMock->expects($this->any()) 
      ->method('hasIdentity') 
      ->will($this->returnValue(true)); 
     $authMock->expects($this->any()) 
      ->method('getIdentity') 
      ->will($this->returnValue($ZfcUserMock)); 
     $this->serviceManager = $this->getApplicationServiceLocator(); 
     $this->serviceManager->setAllowOverride(true); 
     $this->serviceManager->get('ControllerPluginManager')->setService(
      'zfcUserAuthentication', $authMock 
     ); 
    } 

    public function testIndexActionCanBeAccessed() 
    { 
     $this->dispatch('/issue'); 
     $this->assertResponseStatusCode(200); 
     $this->assertModuleName('Issue'); 
     $this->assertControllerName('Issue\Controller\Issue'); 
     $this->assertControllerClass('IssueController'); 
     $this->assertMatchedRouteName('issue'); 
    } 

    public function testAddActionRedirectsAfterValidPost() 
    { 
     $issueTableMock = $this->getMockBuilder('Issue\Model\IssueTable') 
      ->disableOriginalConstructor() 
      ->getMock(); 
     $issueTableMock->expects($this->once()) 
      ->method('saveIssue') 
      ->will($this->returnValue(null)); 
     $this->serviceManager->setService('Issue\Model\IssueTable', $issueTableMock); 
     $postData = array(
      'title' => 'Gun Control', 
      'id' => '', 
     ); 
     $this->dispatch('/issue/add', 'POST', $postData); 
     $this->assertResponseStatusCode(302); 
     $this->assertRedirectTo('/issue'); 
    } 

    public function testEditActionRedirectsAfterValidPost() 
    { 
     $issueTableMock = $this->getMockBuilder('Issue\Model\IssueTable') 
      ->disableOriginalConstructor() 
      ->getMock(); 
     $issueTableMock->expects($this->once()) 
      ->method('saveIssue') 
      ->will($this->returnValue(null)); 
     $this->serviceManager->setService('Issue\Model\IssueTable', $issueTableMock); 
     $issueTableMock->expects($this->once()) 
      ->method('getIssue') 
      ->will($this->returnValue(new \Issue\Model\Issue())); 
     $postData = array(
      'title' => 'Gun Control', 
      'id' => '1', 
     ); 
     $this->dispatch('/issue/edit/1', 'POST', $postData); 
     $this->assertResponseStatusCode(302); 
     $this->assertRedirectTo('/issue'); 
    } 

    public function testDeleteActionRedirectsAfterValidPost() 
    { 
     $postData = array(
      'title' => 'Gun Control', 
      'id' => '1', 
     ); 
     $this->dispatch('/issue/delete/1', 'POST', $postData); 
     $this->assertResponseStatusCode(302); 
     $this->assertRedirectTo('/issue'); 
    } 
} 

<?php 

namespace Issue\Controller; 

use Zend\Mvc\Controller\AbstractActionController; 
use Zend\View\Model\ViewModel; 
use Issue\Model\Issue; 
use Issue\Form\IssueForm; 

class IssueController extends AbstractActionController 
{ 
    protected $issueTable; 

    public function indexAction() 
    { 
     if (!$this->zfcUserAuthentication()->hasIdentity()) { 
      return; 
     } 
     return new ViewModel(
      array(
       'issues' => $this->getIssueTable()->fetchAll(
        $this->zfcUserAuthentication()->getIdentity()->getId() 
       ), 
      ) 
     ); 
    } 

    public function addAction() 
    { 
     if (!$this->zfcUserAuthentication()->hasIdentity()) { 
      return $this->redirect()->toRoute('issue'); 
     } 
     $form = new IssueForm(); 
     $form->get('submit')->setValue('Add'); 
     $request = $this->getRequest(); 
     if ($request->isPost()) { 
      $issue = new Issue(); 
      $form->setInputFilter($issue->getInputFilter()); 
      $form->setData($request->getPost()); 
      if ($form->isValid()) { 
       $issue->exchangeArray($form->getData()); 
       $this->getIssueTable()->saveIssue(
        $issue, 
        $this->zfcUserAuthentication()->getIdentity()->getId() 
       ); 
       // Redirect to list of issues 
       return $this->redirect()->toRoute('issue'); 
      } 
     } 
     return array('form' => $form); 
    } 

    public function editAction() 
    { 
     if (!$this->zfcUserAuthentication()->hasIdentity()) { 
      return $this->redirect()->toRoute('issue'); 
     } 
     $id = (int)$this->params()->fromRoute('id', 0); 
     if (!$id) { 
      return $this->redirect()->toRoute(
       'issue', array(
       'action' => 'add' 
      ) 
      ); 
     } 
     // Get the Issue with the specified id. An exception is thrown 
     // if it cannot be found, in which case go to the index page. 
     try { 
      $issue = $this->getIssueTable()->getIssue($id); 
     } catch (\Exception $ex) { 
      return $this->redirect()->toRoute(
       'issue', array(
       'action' => 'index' 
      ) 
      ); 
     } 
     $form = new IssueForm(); 
     $form->bind($issue); 
     $form->get('submit')->setAttribute('value', 'Edit'); 
     $request = $this->getRequest(); 
     if ($request->isPost()) { 
      $form->setInputFilter($issue->getInputFilter()); 
      $form->setData($request->getPost()); 
      if ($form->isValid()) { 
       $this->getIssueTable()->saveIssue(
        $issue, 
        $this->zfcUserAuthentication()->getIdentity()->getId() 
       ); 
       // Redirect to list of issues 
       return $this->redirect()->toRoute('issue'); 
      } 
     } 
     return array(
      'id' => $id, 
      'form' => $form, 
     ); 
    } 

    public function deleteAction() 
    { 
     if (!$this->zfcUserAuthentication()->hasIdentity()) { 
      return $this->redirect()->toRoute('issue'); 
     } 
     $id = (int)$this->params()->fromRoute('id', 0); 
     if (!$id) { 
      return $this->redirect()->toRoute('issue'); 
     } 
     $request = $this->getRequest(); 
     if ($request->isPost()) { 
      $del = $request->getPost('del', 'No'); 
      if ($del == 'Yes') { 
       $id = (int)$request->getPost('id'); 
       $this->getIssueTable()->deleteIssue($id); 
      } 
      // Redirect to list of issues 
      return $this->redirect()->toRoute('issue'); 
     } 
     return array(
      'id' => $id, 
      'issue' => $this->getIssueTable()->getIssue($id) 
     ); 
    } 

    public function getIssueTable() 
    { 
     if (!$this->issueTable) { 
      $sm = $this->getServiceLocator(); 
      $this->issueTable = $sm->get('Issue\Model\IssueTable'); 
     } 
     return $this->issueTable; 
    } 
}