Unit Testing Kohana v3 – PHPUnit

Like Zend Framework, I also created unit testing for Kohana v3 based projects. It is done seamlessly with PHPUnit of course. The following are the simple steps I’ve done to setup a PHPUnit test environment for Kohana v3.

UPDATE: I have written a more updated article on unit testing in Kohana v3. Now, it is using the official unittest module. Check if out: Kohana Unit Testing – Finally

Overview

My current environment is the following:

Kohana version: Kohana v3.0.3
PHPUnit version: 3.4.11

The tests directory for all our tests are located at application/tests , see the image below:

Now let us dive into the details of the test environment.

Configurations

The next thing we need to configure is the PHPUnit’s bootstrap/test helper and the phpunit.xml. In kohana v3, there is a bootstrap file under application directory, however, it the displays the response by default (HTML output), so we need to create another bootstrap just for unit tests. We will name it testbootstrap and will be created later.

Under the application/tests directory, create a file named phpunit.xml. This is going to be the contents.

<phpunit bootstrap="bootstrap.php" colors="true">
    <testsuite name="ApplicationTestSuite">
        <directory>./classes</directory>
    </testsuite>
    <filter>
        <whitelist>
            <directory suffix=".php">../tests</directory>
            <exclude>
			<directory suffix="*">../cache</directory>
			<directory suffix="*">../config</directory>
			<directory suffix="*">../logs</directory>
                <directory suffix=".php">../views</directory>
                <file>../bootstrap.php</file>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

It tells PHPUnit to use the bootstrap.php as the test helper and the test cases are located at the classes directory (under tests).

Next, we are going to create the test helper. This is going to be the content of bootstrap.php.

<?php

require_once 'PHPUnit/Framework.php';

ini_set('display_errors', 'On');

/**
 * The directory in which your application specific resources are located.
 * The application directory must contain the config/kohana.php file.
 *
 * @see  http://docs.kohanaphp.com/install#application
 */
$application = '../';

/**
 * The directory in which your modules are located.
 *
 * @see  http://docs.kohanaphp.com/install#modules
 */
$modules = '../../modules';

/**
 * The directory in which the Kohana resources are located. The system
 * directory must contain the classes/kohana.php file.
 *
 * @see  http://docs.kohanaphp.com/install#system
 */
$system = '../../system';

/**
 * The default extension of resource files. If you change this, all resources
 * must be renamed to use the new extension.
 *
 * @see  http://docs.kohanaphp.com/install#ext
 */
define('EXT', '.php');

/**
 * Set the PHP error reporting level. If you set this in php.ini, you remove this.
 * @see  http://php.net/error_reporting
 *
 * When developing your application, it is highly recommended to enable notices
 * and strict warnings. Enable them by using: E_ALL | E_STRICT
 *
 * In a production environment, it is safe to ignore notices and strict warnings.
 * Disable them by using: E_ALL ^ E_NOTICE
 * 
 * When using a legacy application with PHP >= 5.3, it is recommended to disable
 * deprecated notices. Disable with: E_ALL &amp; ~E_DEPRECATED
 */
error_reporting(E_ALL | E_STRICT);

/**
 * End of standard configuration! Changing any of the code below should only be
 * attempted by those with a working knowledge of Kohana internals.
 *
 * @see  http://docs.kohanaphp.com/bootstrap
 */

// Set the full path to the docroot
define('DOCROOT', realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '../../..').DIRECTORY_SEPARATOR);

// Make the application relative to the docroot
if ( ! is_dir($application) AND is_dir(DOCROOT.$application))
	$application = DOCROOT.$application;

// Make the modules relative to the docroot
if ( ! is_dir($modules) AND is_dir(DOCROOT.$modules))
	$modules = DOCROOT.$modules;

// Make the system relative to the docroot
if ( ! is_dir($system) AND is_dir(DOCROOT.$system))
	$system = DOCROOT.$system;

// Define the absolute paths for configured directories
define('APPPATH', realpath($application).DIRECTORY_SEPARATOR);
define('MODPATH', realpath($modules).DIRECTORY_SEPARATOR);
define('SYSPATH', realpath($system).DIRECTORY_SEPARATOR);

// Define the full URL for the website base path
define('WEBPATH', 'http://localhost/projectname/');

// Clean up the configuration vars
unset($application, $modules, $system);

if (file_exists('install'.EXT))
{
	// Load the installation check
	return include 'install'.EXT;
}

// Load the base, low-level functions
require SYSPATH.'base'.EXT;

// Load the core Kohana class
require SYSPATH.'classes/kohana/core'.EXT;

if (is_file(APPPATH.'classes/kohana'.EXT))
{
	// Application extends the core
	require APPPATH.'classes/kohana'.EXT;
}
else
{
	// Load empty core extension
	require SYSPATH.'classes/kohana'.EXT;
}

// Bootstrap the application
require APPPATH.'testbootstrap'.EXT;

There are two things that I customized here. First is the DOCROOT path where my DOCROOT here is several levels higher than the normal Kohana v3 directory structure. My structure looks like this:

project_dir
    some_obscure_dir
        application
            classes
            tests
                phpunit.xml
        system
        modules
    js
    css
    index.php

Where the project files are contained under an obscured directory. If your directory structure is different, adjust it accordingly.

The next thing is that I used application/testbootstrap.php to bootstrap the kohana project. It is just a copy of application/bootstrap.php but commented out the last part which sends the output to the client. We don’t need to send output when unit testing.

Here is the content of the testbootstrap.php file.

<?php defined('SYSPATH') or die('No direct script access.');

//-- Environment setup --------------------------------------------------------

/**
 * Set the default time zone.
 *
 * @see  http://docs.kohanaphp.com/about.configuration
 * @see  http://php.net/timezones
 */
date_default_timezone_set('Asia/Manila');

/**
 * Set the default locale.
 *
 * @see  http://docs.kohanaphp.com/about.configuration
 * @see  http://php.net/setlocale
 */
setlocale(LC_ALL, 'en_US.utf-8');

/**
 * Enable the Kohana auto-loader.
 *
 * @see  http://docs.kohanaphp.com/about.autoloading
 * @see  http://php.net/spl_autoload_register
 */
spl_autoload_register(array('Kohana', 'auto_load'));

/**
 * Register namespaces here to autoload Zend Framework like classes
 * Those classes must have vendor prefix, for example:
 * My_Super_Class, the prefix is 'My_'
 * Register the prefix so that native kohana autoloading will not be used
 * These classes must exists only in application directory (APPPATH)
 */
Kohana::registerNamespace('Dc_');
Kohana::registerNamespace('Zend_');

/**
 * Enable the Kohana auto-loader for unserialization.
 *
 * @see  http://php.net/spl_autoload_call
 * @see  http://php.net/manual/var.configuration.php#unserialize-callback-func
 */
ini_set('unserialize_callback_func', 'spl_autoload_call');

//-- Configuration and initialization -----------------------------------------

/**
 * Initialize Kohana, setting the default options.
 *
 * The following options are available:
 *
 * - string   base_url    path, and optionally domain, of your application   NULL
 * - string   index_file  name of your index file, usually "index.php"       index.php
 * - string   charset     internal character set used for input and output   utf-8
 * - string   cache_dir   set the internal cache directory                   APPPATH/cache
 * - boolean  errors      enable or disable error handling                   TRUE
 * - boolean  profile     enable or disable internal profiling               TRUE
 * - boolean  caching     enable or disable internal caching                 FALSE
 */
Kohana::init(array(
				'base_url' 		=> '/projectname/',
				'index_file'	=> 'index.php',
				'charset'		=> 'utf-8',
				'cache_dir'		=> APPPATH.'/cache',
				'errors'		=> TRUE,
				'profile'		=> TRUE,
				'caching'		=> FALSE
			));

/**
 * Attach the file write to logging. Multiple writers are supported.
 */
Kohana::$log->attach(new Kohana_Log_File(APPPATH.'logs'));

/**
 * Attach a file reader to config. Multiple readers are supported.
 */
Kohana::$config->attach(new Kohana_Config_File);

/**
 * Enable modules. Modules are referenced by a relative or absolute path.
 */
Kohana::modules(array(
	// 'auth'       => MODPATH.'auth',       // Basic authentication
	// 'codebench'  => MODPATH.'codebench',  // Benchmarking tool
	'database'   	=> MODPATH.'database',   // Database access
	// 'image'      => MODPATH.'image',      // Image manipulation
	// 'orm'        => MODPATH.'orm',        // Object Relationship Mapping
	// 'pagination' => MODPATH.'pagination', // Paging of results
	// 'userguide'  => MODPATH.'userguide',  // User guide and API documentation
	));

/**
 * Set the routes. Each route must have a minimum of a name, a URI and a set of
 * defaults for the URI.
 */
Route::set('default', '(<controller>(/<action>(/<id>)))')
	->defaults(array(
		'controller' => 'welcome',
		'action'     => 'index',
	));

/**
 * Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
 * If no source is specified, the URI will be automatically detected.
 */
//commented out for PHPUnit
/*
echo Request::instance()
	->execute()
	->send_headers()
	->response;
*/

Write Tests

Now that we configured our Kohana environment, we are going to create our sample test. Under the application/tests directory, create a directory named classes. Under classes, create a file named SampleTest.php.

Now let’s write our sample test on SampleTest.php.

<?php defined('SYSPATH') or die('No direct script access.');

class SampleTest extends PHPUnit_Framework_TestCase
{
    public function testEqual()
    {
        $obj = new Dc_Uuid;
        $this->assertEquals(2, (1+1));
    }
}

Run Tests

Now it’s time to run our sample test. Launch your favorite terminal program, I used Konsole for example. Change directory to your tests directory.

cd /var/www/htdocs/projectname/some_obscure_dir/application/tests
phpunit

You will get an output like below (but a bit different of course). Please note that I run this test on a real project, thus there are several tests that are executed, thus output will be different to yours.

Enjoy Kohana.

This entry was posted in Kohana v3, PHPUnit and tagged , , , , , , . Bookmark the permalink.

Related Posts

5 Responses to Unit Testing Kohana v3 – PHPUnit

  1. Pingback: Kohana Unit Testing – Finally | Lysender's Daily Log Book

  2. Pingback: Tweets that mention Unit Testing Kohana v3 – PHPUnit | Lysender's Daily Log Book -- Topsy.com

  3. circass says:

    Hi, i have a problem about using phpunit with my kohana enviroanment for testing.
    I have to write a test for a function which calls Request::… . When i wrote the function for testing that function it is always seying the same thing. try to access a member function with a non object ! What i understand is Request::instance or Request:initial is never created !
    Can you help me about that ? What can i do for testing that kind of things ?

    Best

  4. lysender says:

    Hi circass,

    You may use behat for that. Also got that tip from Kohana forum.

  5. circass says:

    Hi lysender,
    I found an other solution like adding these initialisation parameters in configuration files for phpunit and I created the server parameters in the phpunit scripts. With that way all my problems solved.
    Thanx

Leave a Reply

Your email address will not be published. Required fields are marked *