1
votes

We're using ZF2 for an web-application and want to test it with phpunit (v4.8.9). Within this application we've got a scheme-route, to be able to switch between http/https-context (Doesnt matter why...). The route looks like this:

'http' => array(
    'type' => 'Scheme',
    'options' => array(
        'scheme' => 'http',
        'defaults' => array(
            'http' => true
        )
    ),
    'child_routes' => array(
        'search' => array(
            'type'    => 'segment',
            'options' => array(
                'route' => '/search[/:keyword[/:page]]',
                'constraints' => array(
                    'page' => '[1-9]+[0-9]*'
                ),
                'defaults' => array(
                    'controller'    => SearchController::class,
                    'action'        => 'search',
                ),
            ),
        ),
    ),
),
'https' => array(
    'type' => 'Scheme',
    'options' => array(
        'scheme' => 'https',
        'defaults' => array(
            'https' => true
        )
    ),
    'child_routes' => array(
        'search' => array(
            'type'    => 'segment',
            'options' => array(
                'route' => '/search[/:keyword[/:page]]',
                'constraints' => array(
                    'page' => '[1-9]+[0-9]*'
                ),
                'defaults' => array(
                    'controller'    => SearchController::class,
                    'action'        => 'search',
                ),
            ),
        ),
    ),
),

The class of the test looks like this:

class SearchControllerTest extends SynHttpControllerTestCase
{
    public function setUp()
    {
        $this->setApplicationConfig($this->getCurrentBootstrap()->getApplicationConfig());
        parent::setUp();
        $this->getApplicationServiceLocator()->setAllowOverride(true);
    }

    public function testSearchActionCanBeAccessed()
    {
        $this->dispatch('/search');
        $this->assertResponseStatusCode(200);
        $this->assertControllerName(SearchController::class);
        $this->assertControllerClass('SearchController');
        $this->assertActionName('search');
        $this->assertMatchedRouteName('search');
    }
}

FYI: The "SynHttpControllerTestCase" is an extension from the original AbstractHttpControllerTestCase which comes with Zend-Test. It's modified to get the right bootstrap-file in our tests.

If we're running the tests, this error appears:

Fatal error: Call to a member function getParam() on null in C:\xampp\htdocs\git\xxx\vendor\zendframework\zend-test\src\PHPUnit\Controller\AbstractControllerTestCase.php on line 563

We looked into the AbstractControllerTestCase and this line is throwing the error:

$routeMatch = $this->getApplication()->getMvcEvent()->getRouteMatch();

Because the $routeMatch-Object is empty. We've some other controllers and tests within our application, they're all fine and not affected from this problem, cause the routes to these controllers arent scheme-routes.

Do you have any ideas how to solve this? In advance: we're not able to use static https-routes in this case.

1

1 Answers

0
votes

There is a lot of official documentation on how to write a proper controller test. In your setUp method you need to attach a Router instance to a RouteMatch instance which you attach to a MvcEvent in the controller.

protected function setUp()
{
    $serviceManager = Bootstrap::getServiceManager();
    $this->controller = new IndexController();
    $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);
}

Then you can call dispatch.

UPDATE

Can you not set your route match object like this:

$routeParams  = array('controller' => 'search', 'action' => 'search');
$routeMatch   = new RouteMatch($routeParams);
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);

$event        = new MvcEvent();
$event->setRouter($router);
$event->setRouteMatch($routeMatch);

$this->getApplication()->setMvcEvent($event);