2011年12月18日 星期日

PHPUnit_TestMore

PHPUnit_TestMore

PHPUnit is a great unit testing framework for PHP http://www.phpunit.de/manual/current/en/.

This helper library PHPUnit_TestMore https://github.com/c9s/PHPUnit_TestMore is for PHPUnit Test Framework, which brings the good things from the Test::More http://search.cpan.org/~mschwern/Test-Simple-0.98/lib/Test/More.pm library of Perl into PHP platform.

The original PHPUnit TestCase is trivial, for example:

function test() {
    $this->assertTrue( true );
    $this->assertArrayHasKey('foo', array('bar' => 'baz'));
    $this->assertClassHasAttribute('foo', 'stdClass');
    $this->assertContains(4, array(1, 2, 3));
}

If you write Perl, you must be familiar with this:

#!/usr/bin/env perl
use Test::More tests => 10;
$val = 1;
ok( $val );
is( 1, 1 );

Which is much simpler and easy, let you not to hate writing unit tests.

Then here is the PHP version's Test::More:

class FooTest extends PHPUnit_Framework_TestCase 
{
    function test() 
  {
        ok(1);
        ok(true);
        ok('string');
        not_ok(false);
  }
}

Setup phpunit.xml configuration

Create a file named phpunit.xml, and set the attribute printerClass to PHPUnit_Util_Log_TAP:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
        backupGlobals="false"
        verbose="true"
        syntaxCheck="true"
        convertErrorsToExceptions="true"
        convertNoticesToExceptions="true"
        convertWarningsToExceptions="true"
        printerClass="PHPUnit_Util_Log_TAP">
<testsuites>
    <testsuite name="PHPUnit">
    <directory suffix="Test.php">tests</directory>
    </testsuite>
</testsuites>
</phpunit>

In your bootstrap.php, require the TestMore helper.

require 'tests/PHPUnit_TestMore.php';

How it works

To reduce unit testing code, there is a function called debug_backtrace, which returns a call stack of current function call.

Here is some ideal PHP code synopsis for testing:

function test()
{
    ok( 1 );
    is( 1, 1);
}

To let the ok function get the caller object, we use debug_backtrace to call the original assertNotEmpty method:

function ok( $v , $msg = null )
{
    $stacks = debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT );                      $testobj = $stacks[1]['object'];
    $testobj->assertTrue( $v ? true : false , $msg );
}