1

Currently I am trying to refresh and expand my knowledge of Zend Framework 2 and I'm looking at Zend's User Guide, specifically the page on Routing and Controllers.

Seeing four almost identical test functions for asserting actions can be accessed offended my notion of best practice, so I rewrote the last four methods, adding in a fifth as a helper, like so:

        private function assertActionCanBeAccessed ($action)
    {
        $this->routeMatch->setParam('action', $action);

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

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


    public function testAddActionCanBeAccessed()    { $this->assertActionCanBeAccessed('add'); }
    public function testDeleteActionCanBeAccessed() { $this->assertActionCanBeAccessed('delete'); }
    public function testEditActionCanBeAccessed()   { $this->assertActionCanBeAccessed('edit'); }
    public function testIndexActionCanBeAccessed()  { $this->assertActionCanBeAccessed('index'); }

When I ran PHPUnit, this worked fine.

But it seems to me that this method would likely be useful for other controllers. And, besides, I just want to know how to make methods commonly available to throughout my code.

So I wrote the following class:

<?php

class ActionTestToolkit
{
    public static function assertActionCanBeAccessed ($testcase, $action)
    {
        $testcase->routeMatch->setParam('action', $action);

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

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

?>

... and saved it to vendor/Flux/library/ActionTestToolkit

Without Zend Framework, I would have just used require_once, but I'm finding it impossible to get the path right within this tangled web of files. And Googling the subject seems to suggest that maybe I should be doing something with the autoloader

Can someone please tell me exactly what code I should/must add to

  • public/index.php
  • module/Album/test/AlbumTest/Controller/AlbumControllerTest.php
  • and/or any other file(s)

in order that I can replace the lines

public function testAddActionCanBeAccessed() 
       { $this->assertActionCanBeAccessed('add'); }

with

public function testAddActionCanBeAccessed() 
       { ActionTestToolkit::assertActionCanBeAccessed($this, 'add'); }

This has been driving me nuts all evening, so thanks in advance!

j0k
  • 22,600
  • 28
  • 79
  • 90
Brian Kessler
  • 2,187
  • 6
  • 28
  • 58

3 Answers3

0

simply include the autoload in PHPUnit's bootstrap.

See how ZF2 run the tests

https://github.com/zendframework/zf2/blob/master/tests/phpunit.xml.dist

https://github.com/zendframework/zf2/blob/master/tests/Bootstrap.php

Maks3w
  • 6,014
  • 6
  • 37
  • 42
  • 1
    Maks, Thanks for the response, but I have trouble keeping "simply" and "Zend" into the same universe. Other PHP frames such as Kohana and Symfony seemed much simpler. I'll take a more indepth look at those files later, but I think I may be looking for a more generic solution, so I could make reusable code, not just for testing but for whatever uses I have. – Brian Kessler Nov 11 '12 at 18:19
  • This is not specific framework configuration, the config is related with the directory structure. Another option is add phpunit/phpunit as composer's dependency, in this mode PHPUnit has hardcoded the relative path to Composer's vendor autoload. – Maks3w Nov 12 '12 at 07:55
  • 1
    Maks, I think what I could really use to help me wrap my head around this is a concrete but stripped down example (complete with fully qualified folder and file names) which demonstrates (1) Adding a namespace to the Zend autoloader; (2) including a class within the namespace; (3) including a class within a Zend php script; and (4) using a method from said class within said script.... Ideally, the starting point for this should be the Zend Skeleton. – Brian Kessler Nov 12 '12 at 12:40
0

In your module create tests folder and there place phpunit.xml

    <?xml version="1.0" encoding="UTF-8"?>

<phpunit
    bootstrap="./bootstrap.php"
    colors="true"
    backupGlobals="false"
>
    <testsuites>
        <testsuite name="FluxModule Test Suite">
            <directory>./</directory>
        </testsuite>
    </testsuites>

</phpunit>

And bootstrap.php where you say where are classes for your module

    <?php

chdir(__DIR__);

if (!(@include_once __DIR__ . '/../vendor/autoload.php') && !(@include_once __DIR__ . '/../../../vendor/autoload.php')) {
    throw new RuntimeException('vendor/autoload.php could not be found. Did you run `php composer.phar install`?');
}

$autoloader = new Zend\Loader\StandardAutoloader(array('autoregister_zf' => true));
$autoloader->registerNamespaces(array('Flux' => __DIR__ . '/../src/Flux'));
$autoloader->register();
Zdenek Machek
  • 1,758
  • 1
  • 20
  • 30
  • Cheers for this, but I get the feeling we're missing a little bit of information here since my file isn't at "../src/Flux" but rather "vendor/Flux/library/ActionTestToolkit". Should I move it? or change the registerNamespace array? And I have no "vendor/autoload.php"; is this something I need to create? If so, how? – Brian Kessler Nov 12 '12 at 07:32
0

I think the first question would be if are you using composer(https://getcomposer.org/)? Seeming that you have a vendors folder seems to indicate so, but then you don't have a vendor/autoload.php.. What else do you have in that folder..?

I found that using composer to handle autoload simplified things quite a bit, and it integrates really well with zf2 (which will make use of the composer autoload if possible)...Also it makes inclusion of additional code libraries from both the web but also other git repositories on the same machine really easy (so you could make your assertion libraries available across projects)..But I digress...

As an example, here is what I put into my composer.json to be able to autoload files from a manually created '/src' folder (using 'Foo' as my vendor name):

{ /* ... */
    "autoload": {
        "psr-0": {"Foo": "src/" }
    }
}

For example, take the file 'src/Foo/Form/View/Helper/FormElement.php': I could reference it in my tests as '\Foo\Form\View\Helper\FormElement'. Note that composer also allows you to use psr-4, which flattens the folder structure somewhat.

Also note that you will have to, as suggested by other posts, include the composer autoloader in the Boostrap.php:

phpunit.xml (in /tests folder): .. bootstrap="./Bootstrap.php" ..

Bootstrap.php (in /tests folder):

chdir(dirname(__DIR__));


// Setup autoloading
require 'init_autoloader.php';

Getting started using composer might seem a little overhead, but it simplifies things enormously in the long run...

hope this helps a little :)

malte
  • 1,439
  • 1
  • 11
  • 12