作者: 溪水清澈
<?php
/**
* 测试类基类
* 继承时, 参考assertEqual写
*/
class TestUnitBase
{
/**
* 测试的返回结果, 格式如下:
* array(
* 'TestA' => array(
* 'info' => TestA方法的相关信息, 参见debug_backtrace()的返回值,
* 'methods' => array(
* 0 => array(
* 'pass' => bool 测试通过与否
* 'desc' => 第三个参数
* 'info' => assertXXX方法的相关信息
* ),
* 1 => ...
* )
* ),
* );
*/
public $testResult;
/**
* 具体的值与期望值判断, 并对结果进行赋值
*/
final public function assertEqual( $value, $expectedValue = true, $desc = '' )
{
$pass = $value == $expectedValue;
$this -> assignResult( $pass, $desc );
}
/**
* 对结果进行赋值
* 每执行一个assertXXX,
* 把这个assertXXX的测试结果放到以testXXX为键的结果数组中.
*/
final private function assignResult( $result, $desc )
{
$tm = $this -> getTestMethod();
$am = $this -> getAssertMethod();
$testKey = $tm[ 'function' ];
if( empty( $this -> testResult[ $testKey ][ 'info' ] ))
{
$this -> testResult[ $testKey ][ 'info' ] = $tm;
}
$this -> testResult[ $testKey ][ 'methods' ][] = array(
'pass' => $result,
'desc' => $desc,
'info' => $am );
}
/**
* 取得子类中的测试方法的信息
*/
final private function getTestMethod()
{
// 索引3为结果
$backtrace = debug_backtrace();
return $backtrace[ 3 ];
}
/**
* 取得assertXXX方法的信息
*/
final private function getAssertMethod()
{
// 索引2为结果
$backtrace = debug_backtrace();
return $backtrace[ 2 ];
}
}
/**
* 测试管理类, 以类名为参数
* 自动执行testXXX函数
*/
class TestManage
{
private $testClassName;
private $testObject;
/**
* 以类名为参数
*/
public function __construct( $testClassName )
{
$this -> testClassName = $testClassName;
}
/**
* 执行测试
*/
public function exec()
{
if( ! $this -> newObject() )
{
return false;
}
$testMethods = $this -> getAllTestMethods();
foreach( $testMethods as $method )
{
call_user_func( array( $this -> testObject, $method -> name ));
}
$this -> result = $this -> testObject -> testResult;
return $this -> result;
}
/**
* 实例化对象
*/
private function newObject()
{
if( class_exists( $this -> testClassName ))
{
$this -> testObject = new $this -> testClassName;
return true;
}
else
{
return false;
}
}
/**
* 取得测试类的测试方法
* 暂定为以test开头的公共方法(不论大小写);
*/
private function getAllTestMethods()
{
$ref = new ReflectionClass( $this -> testObject );
$methods = $ref -> getMethods( ReflectionMethod::IS_PUBLIC );
foreach( $methods as $method )
{
if( 'test' == strtolower( substr( $method -> name, 0, 4 ))
&& $method -> class == $this -> testClassName )
{
$ret[] = $method;
}
}
return $ret;
}
/**
* 输出报告
*/
public function report()
{
foreach( $this -> result as $res )
{
$class = $res[ 'info' ][ 'class' ];
$method = $res[ 'info' ][ 'function' ];
$type = $res[ 'info' ][ 'type' ];
echo "$class$type$method ## \n";
foreach( $res[ 'methods' ] as $assert )
{
$pass = $assert[ 'pass' ] ? 'pass' : "\terror";
$desc = ( $assert[ 'pass' ] ? "\t" : '' ) . $assert[ 'desc' ];
$assertMethod = $assert[ 'info' ][ 'function' ];
$assertLine = $assert[ 'info' ][ 'line' ];
echo "\t$assertMethod @ $assertLine\t$pass\t$desc\n";
}
echo "\n";
}
}
}
// 以下为测试代码
class TestTest extends TestUnitBase
{
public function testA()
{
$this -> assertEqual( 1, 2, '1 eq 2?' );
$this -> assertEqual( 1, 1, '1 eq 1?' );
$this -> assertEqual( 1, 2, '1 eq 2?' );
}
public function testB()
{
$this -> assertEqual( 'abc', 'def', 'eq?' );
}
}
$test = new TestManage( 'TestTest' );
$test -> exec();
$test -> report();