我已经从http://www.davegardner.me.uk/blog/2011/03/04/mocking-iterator-with-phpunit/实现了mockiterator解决方案,通过创建扩展Zend_Test_PHPUnit_DatabaseTestCase
和Zend_Test_PHPUnit_ControllerTestCase
的类,并将方法放入每个子类。
然而,我也最终在这个过程中添加了一些调整,但是必须在每个类中进行相同的更改以防止发散行为是一种痛苦。
两个Zend类直接从PHPUnit_Framework_TestCase
继承是否有一种方法可以轻松地在PHPUnit和Zend类之间插入一个类,而不涉及直接修改Zend库代码?我想我正在寻找一种简单的方法来做这样的事情:
+-- PHPUnit_Framework_TestCase
|
+-- My_PHPUnit_Framework_TestCase
|
+-- Zend_Test_PHPUnit_ControllerTestCase
+-- Zend_Test_PHPUnit_DatabaseTestCase
我想,作为一种替代方案,我可以在我的库中复制两个Zend类——但是,无论何时上传Zend框架,都可能出现问题,需要从新的Zend测试用例类重写我的库。
在PHP中,你有线性,单亲继承。不幸的是,这意味着如果不修改Zend类的源,就不能插入中间代理类。
如果有必要的话(例如,你有一些东西需要成为两个不同DO类的子类),有一些方法可以伪造多重继承。
使用魔法方法,例如,你可以创建一个多代理:
class MultiProxy
{
private $poxies;
public function __construct( array $arr )
{
$this->proxies = $arr;
}
public function __get( $name )
{
foreach( $this->proxies as $proxy )
{
if( property_exists( $proxy, $name ) )
{
try
{
return $proxy->$name
}
catch( Exception e )
{
// swallow it.
}
}
}
trigger_error( "$name not found on $this" );
}
public function __set( $name, $val )
{
foreach( $this->proxies as $proxy )
{
if( property_exists( $proxy, $name ) )
{
try
{
$proxy->$name = $val;
}
catch( Exception e )
{
// swallow it.
}
}
}
trigger_error( "$name not found on $this" );
}
public function __call( $name, $args )
{
foreach( $this->proxies as $proxy )
{
$proxy = array( $proxy, $name );
if( is_callable( $proxy ) )
{
try
{
call_user_func_array( $proxy, $args );
}
catch( Exception e )
{
// swallow it.
}
}
}
trigger_error( "$name not found on $this" );
}
public function __toString()
{
$ret = "[" . get_class( $this ) . '::{';
foreach( $this->proxies as $proxy )
{
$ret .= get_class( $proxy ) . ',';
}
return substr( $ret, 0, -1 ) .'}]';
}
}
// use:
class Foo{ public $a = 'FOO'; }
class Bar{ public function doSomething(){ echo 'YAY!'; } }
class Baz{ public $a = 'BAZ'; public function doSomething(){ echo 'BAAAZ!'; } }
$foo = new Foo();
$bar = new Bar(); // drink!
$baz = new Baz();
$multi = new MultiProxy( array( $foo, $bar, $baz ) );
$multi->a = 'MULTI!';
echo $multi->a == $foo->a? 1:0;
$multi->doSomething();// YAY!
不要欺骗:将您的公共代码重构为函数,或者最好是一个不从任何东西派生的类。然后仅仅在Zend_Test_PHPUnit_ControllerTestCase和Zend_Test_PHPUnit_DatabaseTestCase中使用这些函数或类(实例化,而不是作为基类)。
复杂继承是邪恶的