Open Source | Technology

Testing eZ Publish extensions using PHPUnit

Below is a tutorial on how to use PHPUnit to test the eZ Publish functionality on your solutions.

GOAL

To use automated tests for custom eZ Publish extensions, the following tasks need to be completed first:

  1. The test case should be able to use eZ Publish INI settings and its override system.  The most important part is the ability to choose site access with DB or other settings, like design, var dir, language etc.
  2. The test case should use the eZ Publish template override system.
  3. The test case should be able to use the eZ Publish kernel/lib functionalities, such as eZPersistentObject, eZContentObject or eZContentObjectTreeNode. This means there is a need to use eZ Publish autoload system.
  4. The test case should be clean and only contain code without any external or additional workarounds, like includes, initializations etc.

IMPLEMENTATION

Fortunately eZ Publish already provides the possibility to solve these problems:
eZScript lets us use settings, site accesses, template system and other features inside a script (standalone php file).
To use autoloads we just need to include autoload.php.

Regarding #4 above, a test case should not contain any initializations or includes.  Therefore, 
we should not use eZScript or to include autoload.php in each test file. Instead, we will use PHPUnit suite loader: PHPUnit_Runner_StandardTestSuiteLoader

Create a new file nxcTestSuiteLoader.php and extend standard suite loader, like this:

Source code    
  1. <?php
  2. /**
  3.  * @author VaL <vd@nxc.no>
  4.  * @copyright Copyright (C) 2011 NXC AS
  5.  * @license GNU GPL v2
  6.  */
  7.  
  8. require_once 'autoload.php';
  9.  
  10. class nxcTestSuiteLoader extends PHPUnit_Runner_StandardTestSuiteLoader
  11. {
  12.     /**
  13.      * @var (eZScript)
  14.      */
  15.     static $Script = false;
  16.  
  17.     /**
  18.      * Exits the script
  19.      *
  20.      * @return (void)
  21.      */
  22.     public static function shutdown()
  23.     {
  24.         self::getScript()->shutdown( 0 );
  25.     }
  26.  
  27.     /**
  28.      * Returns eZScript
  29.      *
  30.      * @return (eZScript)
  31.      */
  32.     protected static function getScript()
  33.     {
  34.         if ( self::$Script )
  35.         {
  36.             return self::$Script;
  37.         }
  38.  
  39.         $scriptSettings = array();
  40.         $scriptSettings['description'] = '';
  41.         $scriptSettings['use-session'] = false;
  42.         $scriptSettings['use-modules'] = true;
  43.         $scriptSettings['use-extensions'] = true;
  44.  
  45.         self::$Script = eZScript::instance( $scriptSettings );
  46.         return self::$Script;
  47.     }
  48.  
  49.     /**
  50.      * Initializes script to use settings, siteaccesses and other ezp features
  51.      *
  52.      * @return (void)
  53.      */
  54.     public static function initialize()
  55.     {
  56.         $script = self::getScript();
  57.         $script->startup();
  58.  
  59.         // Workaround to skip include-path and loader to PHPUnit and to use all eZScripts options in tests
  60.         $options = $script->getOptions( '[include-path][loader]' );
  61.  
  62.         $script->initialize();
  63.     }
  64.  
  65.     /**
  66.      * @reimp
  67.      */
  68.     function load( $suiteClassName, $suiteClassFile = '', $syntaxCheck = FALSE )
  69.     {
  70.         return parent::load( $suiteClassName, $suiteClassFile, $syntaxCheck );
  71.     }
  72.  
  73.     /**
  74.      * @reimp
  75.      */
  76.     public function reload( ReflectionClass $aClass )
  77.     {
  78.         return parent::reload( $aClass );
  79.     }
  80. }
  81.  
  82. register_shutdown_function( array( 'nxcTestSuiteLoader', 'shutdown' ) );
  83. nxcTestSuiteLoader::initialize();
  84.  
  85. ?>

 

Now, we need to let the PHPUnit to use a loader.

There is a list of possibilities:
1. Use –inlude-path argument of PHPUnit:

Source code    
  1. $ cd [PATH TO EZP]; phpunit --include-path=./extension/nxc_extension/classes/ --loader=nxcTestSuiteLoader ./extension/nxc_extension/tests/

 

Or make a shell script:

Source code    
  1. $ echo 'phpunit --include-path=./extension/nxc_tools/classes/TestSuiteLoader/ --loader=nxcTestSuiteLoader $1' > phpunit.sh

 

This is the most useful way to handle tests:

Source code    
  1. $ cd [PATH TO EZP]; [PATH]/phpunit.sh ./extension/nxc_extension/tests/

2. Store suite loader file in a path from php.ini:include_path:

Source code    
  1. $ cd [PATH TO EZP]; phpunit --loader TestSuiteLoader ./extension/nxc_extension/tests/

3. Copy the suite loader file or make symlink to eZ Publish root directory.

Source code    
  1. $ cd [PATH TO EZP]; phpunit --loader TestSuiteLoader ./extension/nxc_extension/tests/

EXAMPLE

Let’s try to make unit tests for real code.

Environment

  1. There is a class named as nxcCache to store/cache some content. It is stored in separate extension nxc_cache and is used as NoSQL database handler.
  2. The class provides possibilities:
    to fetch,
    to store,
    to check for existence/expiry,
    to delete a content.And it uses eZ Publish INI settings to define and configure its functionality.
  3. Simplified usage example:
    Source code    
    1. $cache = new nxcCache( 'key' );
    2. $cache->store( 'content' );
    3. $content = $cache->getContent();
    4. if ( $cache->isExpired( $ttl ) )
    5. {
    6.     $cache->delete();
    7. }

Creating tests

Create a test file:

Source code    
  1. $ cd [PATH TO EZP]; touch extension/nxc_cache/tests/nxcCacheTest.php

Determine what excatly should be tested and write/store tests into above file.

1. First, we need to test main functionality to store a content:

Source code    
  1. public function testStore()
  2. {
  3.     $content = 'content';
  4.     $c1 = new nxcCache( 'test' );
  5.     $c1->store( $content );
  6.     $c2 = new nxcCache( 'test' );
  7.  
  8.     $this->assertEquals( $content, $c2->getContent() );
  9. }

 

2. Test puring content:

Source code    
  1. public function testDelete()
  2. {
  3.     $content = 'content';
  4.     $c = new nxcCache( 'test' );
  5.     $c->store( $content );
  6.     $c->delete();
  7.  
  8.     $this->assertFalse( $c->exists() );
  9. }

 

3. Test existence of content:

Source code    
  1. public function testExists()
  2. {
  3.     $c = new nxcCache( md5( time() ) );
  4.     $this->assertFalse( $c->exists() );
  5.     $c->store( 'content' );
  6.     $this->assertTrue( $c->exists() );
  7.     $c->delete();
  8.     $this->assertFalse( $c->exists() );
  9. }

4. Test if a cache is expired correctly:

Source code    
  1. public function testIsExpired()
  2. {
  3.     $c = new nxcCache( 'test' );
  4.     $c->store( 'content' );
  5.     $this->assertFalse( $c->isExpired( 60 * 60 ) ); // 1 hour
  6.     sleep( 1 );
  7.     $this->assertTrue( $c->isExpired( 1 ) ); // 1 second
  8. }

Results

You can use tests like normal eZScript files. We have the ability to provide any eZScript options to the tests.

“-s site” means all settings will be fetched from siteaccess “site”:

Source code    
  1. $ ./phpunit.sh "./extension/nxc_cache/tests/nxcCacheTest.php -s site"
  2. PHPUnit 3.6.10 by Sebastian Bergmann.
  3.  
  4. ....
  5.  
  6. Time: 1 second, Memory: 6.50Mb
  7.  
  8. OK (4 tests, 7 assertions)

This means all tests are ok.

Source code of nxcCacheTest.php:

Source code    
  1. <?php
  2. /**
  3.  * @author VaL <vd@nxc.no>
  4.  * @copyright Copyright (C) 2011 NXC AS
  5.  * @license GNU GPL v2
  6.  */
  7.  
  8. class nxcCacheTest extends PHPUnit_Framework_TestCase
  9. {
  10.  
  11.     public function testStore()
  12.     {
  13.         $content = 'content';
  14.         $c1 = new nxcCache( 'test' );
  15.         $c1->store( $content );
  16.         $c2 = new nxcCache( 'test' );
  17.  
  18.         $this->assertEquals( $content, $c2->getContent() );
  19.     }
  20.  
  21.     public function testDelete()
  22.     {
  23.         $content = 'content';
  24.         $c = new nxcCache( 'test' );
  25.         $c->store( $content );
  26.         $c->delete();
  27.  
  28.         $this->assertFalse( $c->exists() );
  29.     }
  30.  
  31.     public function testExists()
  32.     {
  33.         $c = new nxcCache( md5( time() ) );
  34.         $this->assertFalse( $c->exists() );
  35.         $c->store( 'content' );
  36.         $this->assertTrue( $c->exists() );
  37.         $c->delete();
  38.         $this->assertFalse( $c->exists() );
  39.     }
  40.  
  41.     public function testIsExpired()
  42.     {
  43.         $c = new nxcCache( 'test' );
  44.         $c->store( 'content' );
  45.  
  46.         $this->assertFalse( $c->isExpired( 60 * 60 ) ); // 1 hour
  47.         sleep( 1 );
  48.         $this->assertTrue( $c->isExpired( 1 ) ); // 1 second
  49.     }
  50.  
  51. }
  52. ?>

LINKS

http://www.phpunit.de/ – PHPUnit
http://share.ez.no/ and http://ez.no/ – eZ Publish

Print this post

0 Responses to "Testing eZ Publish extensions using PHPUnit"

Post a Comment:

Get latest news