7

I have a little problem when creating tests with PHPUnit.

Here is my setup :

protected function setUp()
{
    $serviceManager = Bootstrap::getServiceManager();

    $this->mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
    $this->mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface');
    $this->mockDriver->expects($this->any())->method('checkEnvironment')->will($this->returnValue(true));
    $this->mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($this->mockConnection));
    $this->mockPlatform = $this->getMock('Zend\Db\Adapter\Platform\PlatformInterface');
    $this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
    $this->mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($this->mockStatement));
    $this->adapter = new Adapter($this->mockDriver, $this->mockPlatform);
    $this->sql = new Sql($this->adapter);

    $mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array(), array(), '', false);

    $maiFormuleRevisionTable = $this->getMockBuilder('Maintenance\Model\BDD\PMaiFormulerevisionTable')
        ->setMethods(array())
        ->setConstructorArgs(array($mockTableGateway, $this->adapter, $this->sql))
        ->getMock();
    $maiFormulerevisionService = $this->getMockBuilder('Maintenance\Service\Model\PMaiFormulerevisionService')
        ->setMethods(array())
        ->setConstructorArgs(array($maiFormuleRevisionTable))
        ->getMock();
    $this->assertTrue($maiFormulerevisionService instanceof PMaiFormulerevisionService);

    $this->controller = new RevisionsController($maiFormulerevisionService);

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

Here is the test for my function :

public function testEditFormuleActionCanBeAccessed()
{
    $this->routeMatch->setParam('action', 'loadformule');
    $this->routeMatch->setParam('idformule', '23');
    $result   = $this->controller->dispatch($this->request);
    $response = $this->controller->getResponse();
    $this->assertEquals(200, $response->getStatusCode());
}

And my Controler :

public function loadformuleAction()
{
    try {
        $iStatus = 0;
        $iMaiFormuleRevisionId = (int) $this->params('idformule');

        $oFormule = $this->maiFormulerevisionService->selectByIdOrCreate($iMaiFormuleRevisionId);
        $maiFormulerevisionForm = new PMaiFormulerevisionForm($oFormule);

        if ($this->getRequest()->isPost()) {
            /* etc ... */
        }

        $viewModel = new ViewModel();
        $viewModel->setTerminal(true);
        $viewModel->setVariables([
            'maiFormulerevisionForm' => $maiFormulerevisionForm,
            'iMaiFormuleRevisionId'  => $oFormule->getMaiFormuleRevisionId(),
            'iStatus'                => $iStatus
        ]);
        return $viewModel;
    } catch (\Exception $e) {
        throw new \Exception($e);
    }
}

But when I try to run my test, it shows an error, and I point that my test don't go into my service, when I call it ($this->maiFormulerevisionService) :

1) MaintenanceTest\Controller\RevisionsControllerTest::testEditFormuleActionCanBeAccessed Exception: Argument 1 passed to Maintenance\Form\PMaiFormulerevisionForm::__construct() must be an instance of Maintenance\Model\PMaiFormulerevision, null given

I don't understand why my mock doesn't work ...

Thanks for your answers :)

Edit :

Hum ... when I try this :

$maiFormulerevisionService = new PMaiFormulerevisionService($maiFormuleRevisionTable);

Instead of this :

$maiFormulerevisionService = $this->getMockBuilder('Maintenance\Service\Model\PMaiFormulerevisionService')
            ->setMethods(array())
            ->setConstructorArgs(array($maiFormuleRevisionTable))
            ->getMock();

It goes into the service but not into the TableGateway specified in the constructor of the service ($maiFormuleRevisionTable) ... so it still doesn't work ...

Greco Jonathan
  • 2,517
  • 2
  • 29
  • 54
Amelie
  • 516
  • 3
  • 17
  • Please i'm really blocked. I really need to solve this mock problem and the documentation is really soft ! – Amelie Sep 09 '15 at 10:00
  • Not tested but it looks like you are creating a mock for maiFormulerevisionService that returns null for all methods. So in your controller, this will return null `$oFormule = $this->maiFormulerevisionService->selectByIdOrCreate($iMaiFormuleRevisionId);` Which means this will be passed null in the constructor, which is your error message `$maiFormulerevisionForm = new PMaiFormulerevisionForm($oFormule);` – Ed209 Sep 09 '15 at 13:52
  • I tested but the method on test mode don't go into selectByIdOrCreate() function in fact, so it does not return null ... well, in fact it doesn't go into services, or datagateway classes ... – Amelie Sep 09 '15 at 13:59
  • It would be useful to show the constructor for your controller here. – Benjamin Sep 09 '15 at 14:41

1 Answers1

2

You set a mock, but you also have to set what your mock returns when calling the method selectByIdOrCreate. Since you do:

$oFormule = $this->maiFormulerevisionService->selectByIdOrCreate($iMaiFormuleRevisionId);
$maiFormulerevisionForm = new PMaiFormulerevisionForm($oFormule);

The mock will return null for the selectByIdOrCreate method as long as you don't set a return value for this method.

Try to add a mock method like this:

$mock = $maiFormulerevisionService;
$methodName = 'selectByIdOrCreate';
$stub = $this->returnValue($maiFormuleRevisionTable);

$mock->expects($this->any())->method($methodName)->will($stub);
Wilt
  • 41,477
  • 12
  • 152
  • 203