Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Centralize phpunit test

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on November 19, 2013

zf2-zendframework2 Centralize phpunit test is good when we work at integration test to test all modules we have created. What we need is place autoloader at Bootstrap file, and make ‘ServiceManager Grabber’ to grab services over modules.

1. Preparation :
a. Create tests folder at our ZF2 Application.
tests-folder-prepare
At this phase, we added Bootstrap.php and phpunit.xml as configuration.
b. Write Bootstrap.php

//we create ServiceManagerGrabber class later...
use ModulesTests\ServiceManagerGrabber; 

error_reporting(E_ALL | E_STRICT);

$cwd = __DIR__;
chdir(dirname(__DIR__));

// Assume we use composer
$loader = require_once  './vendor/autoload.php';
$loader->add("ModulesTests\\", $cwd);
$loader->register();

ServiceManagerGrabber::setServiceConfig(require_once './config/application.config.php');
ob_start();

c. Write phpunit.xml
We register module that we add directory of module tests, at this case, named “ModulesTests”.

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

<phpunit
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"

         bootstrap="Bootstrap.php">
    <testsuites>
        <testsuite name="sanzf2">
            <directory suffix=".php">./ModulesTests</directory>
        </testsuite>
    </testsuites>
</phpunit>

d. Based on the phpunit.xml, we then need to create directory named “ModulesTests” to collect test for modules.
moduletests-collect-rev

e. Create ServiceManager Grabber ( as you can see at “ModulesTests” folder )

//inspired from https://github.com/doctrine/DoctrineModule/blob/master/tests/DoctrineModuleTest/ServiceManagerTestCase.php
// thanks to Marco Pivetta

namespace ModulesTests;

use Zend\ServiceManager\ServiceManager;
use Zend\Mvc\Service\ServiceManagerConfig;

class ServiceManagerGrabber
{
    protected static $serviceConfig = null;
    
    public static function setServiceConfig($config)
    {
        static::$serviceConfig = $config;
    }
    
    public function getServiceManager()
    {
        $configuration = static::$serviceConfig ? : require_once './config/application.config.php';
        
        $smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array();
        $serviceManager = new ServiceManager(new ServiceManagerConfig($smConfig));
        $serviceManager->setService('ApplicationConfig', $configuration);
 
        $serviceManager->get('ModuleManager')->loadModules();
        
        return $serviceManager;
    }
}

This class will grab the our ZF2 application config, load Modules, that means the serviceManager of all modules will be returned.

f. create per-module test case
moduletests-collect-hasmodule-collect
At this case, I added directory named “SanDbModellingWithZendDbTest” to test my “SanDbModellingWithZendDb” module. It’s up to us to create other name, or collect or not collect module per directory, but for my perspective, it should be on separate folder per-module test.

2. Write a Test
The test can be formatted like the following :

namespace ModulesTests\SanDbModellingWithZendDbTest\Model;

use PHPUnit_Framework_TestCase;
use ModulesTests\ServiceManagerGrabber;

class AlbumTrackMapperTest extends PHPUnit_Framework_TestCase
{
    protected $serviceManager;
    
    public function setUp()
    {
        $serviceManagerGrabber   = new ServiceManagerGrabber();
        $this->serviceManager = $serviceManagerGrabber->getServiceManager();
    }
    
    public function testJoinLeft()
    {
        $count =  count($this->serviceManager->get('AlbumTrackMapper')->findAll());
        ($count > 0 ) ? $this->assertNotEmpty($count) : $this->assertEmpty($count);
    }
}

3. Run Test
We just need to go to tests folder with command line :

$ cd ~/yourzf2app/tests
$ phpunit

And you will get this :
phpunit-run-cli-zf2

Of course, we can add more folders under “ModulesTests” folder.

Thanks to Marco Pivetta that give me enlightenment to not share one ServiceManager accross different tests.
thanks-to-marco-pivetta-for-suggestion-to-not-share-one-service-accross-different-test

Done ;)

About these ads

15 Responses

Subscribe to comments with RSS.

  1. Max Gulturyan said, on November 19, 2013 at 4:30 pm

    Why?
    1. Every module must contain own tests
    2. General tests mus run all modules tests? like this:

    ../module/Application/test/UnitTest
    ../module/Application/test/FunctionalTests

    ../module/Authentication/test/UnitTest
    ../module/Authentication/test/FunctionalTests

    ../module/Pages/test/UnitTest

    Bootstrap.php:
    setService(‘ApplicationConfig’, $config);
    static::$serviceManager->get(‘ModuleManager’)->loadModules();
    }

    public static function getServiceManager() {
    return static::$serviceManager;
    }

    private static function loadModules(array $modules) {
    foreach ($modules as $moduleName) {
    include SITE_PATH . “/module/$moduleName/Module.php”;
    }
    }

    }

    Bootstrap::init();

  2. Max Kucher said, on November 19, 2013 at 4:38 pm

    sorry

    pastebin.com/PJKGBUbF
    pastebin.com/vzzqBwYn

  3. Artur Bodera said, on November 19, 2013 at 6:30 pm

    That “ob_start();” is redundant – that’s up to phpunit to handle.

    Module tests should live under module dirs, and then it is trivial to include those test suites in phpunit.xml. This makes more sense in zf2 module-oriented context and would allow for easier module promotion in the future.

    phpunit.xml i.e.:

    ./../module/Foo/tests/FooTests

    ./../module/Application/tests/ApplicationTests

    • Artur Bodera said, on November 19, 2013 at 6:30 pm

      The above included xml but your wordpress ate that :P

      • samsonasik said, on November 19, 2013 at 8:58 pm

        Thanks Artur. Yes, of course. the ob_start() is to prevent when header happen accidentally at the test. and for module test, we should provide in module where we provide individually for promotion :P.
        But for whole application, I personally like copy them at one folder :).

  4. Gauthier Delamarre said, on December 18, 2013 at 8:31 pm

    I’m sorry to disagree with both you and Marco, but in my opinion, there should be no Service Manager at all.

    Classes making use of ServiceManager should be provided with a mocked ServiceManager whenever it’s necessary for the current test only… and it should also return mocked services, not actual services.

    If you absolutely need the ServiceManager with the actual application configuration, so probably isn’t your test a unit test, but rather a functional test ;)

  5. Chris said, on January 9, 2014 at 9:36 am

    I like this idea. However, what are you doing for loading Classes?

    PHP Fatal error: Class ‘MyModule\Mapper\User’ not found in /var/www/somesite.com/htdocs/tests/ModulesTests/MyModuleTest/Mapper/UserTest.php on line 15

    and i’m declaring it as: 15) $foo = new \MyModule\Mapper\User();

    • samsonasik said, on January 9, 2014 at 1:38 pm

      nothing, just define getAutoloaderConfig() at your Module class with common code for that function. You should have MyModule\Mapper (represented as folders) namespace under MyModule/scr folder

      • Chris said, on January 9, 2014 at 8:13 pm

        Hurrah! Thanks for the tip. I placed

        public function setUp()
        {
        AutoloaderFactory::factory(array(
        ‘Zend\Loader\ClassMapAutoloader’ => array(
        __DIR__ . ‘/autoload_classmap.php’,
        ),
        ‘Zend\Loader\StandardAutoloader’ => array(
        ‘namespaces’ => array(
        __NAMESPACE__ => __DIR__ . ‘/src/’ . __NAMESPACE__
        )
        )
        ));
        $this->mapper = new \MyModule\Mapper\User();
        }

        in the TestModule and this connected. I think that’s what you meant to do. This won’t drag performance down, if I have a lot of test models/mappers will it?

      • samsonasik said, on January 9, 2014 at 9:49 pm

        no, place that at Module Class, see the docs please http://zf2.readthedocs.org/en/latest/user-guide/modules.html and configure Bootstrap.php correctly.

      • Chris said, on January 10, 2014 at 12:16 am

        Done. Much appreciated. This will help a LOT with getting phpunit kicked off with the git pre-commit/pre-receive hooks and kicking off a Jenkins job.

        Do you use the phpunit code coverage tool, how useful is it to you?

      • samsonasik said, on January 10, 2014 at 9:42 am

        yes, I used what @ocramius provide http://ocramius.github.io/blog/automated-code-coverage-check-for-github-pull-requests-with-travis/ it is very usefull when I’m too lazy to check deploy on jenkins.

  6. Rayhan said, on January 19, 2014 at 6:48 am

    Thank you so much. This is exaclty what I was looking for. I’ll try this as soon as can.

  7. Azhar said, on August 22, 2014 at 6:05 pm

    is the where method matches the string into database by using Db\sql like you are using the below code ???

    $select->where(array(‘title’ => ‘abracadabra’));


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 259 other followers

%d bloggers like this: