lucatume / tdd-helpers
PHP 5.2 的 TDD 辅助工具
Requires
- php: >=5.2.0
Requires (Dev)
This package is not auto-updated.
Last update: 2015-12-05 10:25:03 UTC
README
该软件包提供两个用于全局定义函数和变量的适配器以及一个静态模拟类。
这些适配器满足了我将 TDD 技术应用于 WordPress 插件和主题开发的需求。
适配器
函数适配器
将全局定义的函数的调用包装在方法调用中。如果 some_function
是在全局作用域中定义的函数,则可以使用适配器调用它,例如:
$adapter = new tad_FunctionsAdapter();
$var = $adapter->some_function();
该适配器使用接口以实现更灵活的测试模拟
$mockF = $this->getMock('tad_FunctionsAdapterInterface');
全局变量适配器
允许通过对象方法方式访问超级全局变量。
访问 $GLOBALS['foo']
的示例
$g = new tad_GlobalsAdapter();
$foo = $g->globals('foo');
要获取超级全局数组,请不带参数调用函数,例如,要获取 $_SERVER
数组
$g = new tad_GlobalsAdapter();
$g->server();
静态模拟器
一个测试辅助工具,可以以某种方式和限制来模拟静态方法调用。
要测试的类应允许进行类名注入,例如:
public function __construct($var1, $var2, $util = 'StaticClass')
{
$this->util = $util;
$var = $this->util::doSomething();
}
然后在测试文件中
class StaticClass extends tad_StaticMocker
{}
class ClassNameTest extends \PHPUnit_Framework_TestCase
{
public function test_construct_calls_static_class_doSomething()
{
// Create a stub for the SomeClass class.
$stub = $this->getMock('SomeClass');
// Configure the stub.
$stub->expects($this->any())
->method('doSomething')
->will($this->returnValue('foo'));
StaticClass::_setListener($stub);
$sut = new ClassName('some', 'var', 'StaticClass');
}
}
可测试的对象
abstract
类 tad_TestableObject
旨在用作任何打算使用 TDD 技术开发的类的父类,以便更快地对一个或多个方法依赖项进行模拟。测试类似于以下类的类:
class ClassOne{
protected $d;
public function __construct(D $d){
$this->d = $d;
}
public function methodOne(A $a, BInterface $b, CInterface $c){
$a->method();
$b->method();
$c->method();
$this->d->method();
}
}
将需要模拟 A
和 D
类的实例以及 BInterface
和 CInterface
接口的实例
// file ClassOneTest.php
public function test_methodOne_will_call_methods(){
$mockA = $this->getMock('A', array('method'));
$mockBInterface = $this->getMock('BInterface', array('method'));
$mockCInterface = $this->getMock('CInterface', array('method'));
$mockD = $this->getMock('D', array('method'));
$mockA->expects($this->once())->method('method');
$mockBInterface->expects($this->once())->method('method');
$mockCInterface->expects($this->once())->method('method');
$mockD->expects($this->once())->method('method');
$sut = new ClassOne($mockD);
$sut->methodOne();
}
tad_TestableObject
类中定义的 getMocks
方法允许在存在 DocBlock 注释的情况下,将待测试的类重写为添加 DocBlock 注释的类
class ClassOne extends tad_TestableObject {
protected $d;
/**
* @depends D
*/
public function __construct(D $d){
$this->d = $d;
}
/**
* @depends A, BInterface, CInterface
*/
public function methodOne(A $a, BInterface $b, CInterface $c){
$a->method();
$b->method();
$c->method();
$this->d->method();
}
}
并将测试方法重写为
// file ClassOneTest.php
public function test_methodOne_will_call_methods(){
$mockedDependencies = ClassOne::getMocksFor(array('__construct', 'methodOne'))
$mockDependencies->A->expects($this->once())->method('method');
$mockDependencies->BInterface->expects($this->once())->method('method');
$mockDependencies->CInterface->expects($this->once())->method('method');
$mockDependencies->D->expects($this->once())->method('method');
$sut = new ClassOne($mockedDependencies->$mockD);
$sut->methodOne();
}
或者可以使用 getMocksArrayFor
方法以数组形式检索模拟,例如:
// file ClassOneTest.php
public function test_methodOne_will_call_methods(){
extract(ClassOne::getMocksArrayFor(array('__construct', 'methodOne')));
$A->expects($this->once())->method('method');
$BInterface->expects($this->once())->method('method');
$CInterface->expects($this->once())->method('method');
$D->expects($this->once())->method('method');
$sut = new ClassOne($D);
$sut->methodOne();
}
tad_DependencyMocker
使用 tad_DependencyMocker
类也可以对未扩展 tad_TestableObject
类的类进行上述所有模拟。如果一个类的 DocBlocks 设置如下,但未扩展 tad_TestableObject
类
class ClassOne {
protected $d;
/**
* @depends D
*/
public function __construct(D $d){
$this->d = $d;
}
/**
* @depends A, BInterface, CInterface
*/
public function methodOne(A $a, BInterface $b, CInterface $c){
$a->method();
$b->method();
$c->method();
$this->d->method();
}
}
则其方法依赖项仍然可以进行模拟,例如:
// file ClassOneTest.php
public function test_methodOne_will_call_methods(){
$extraMethods = array(
'BInterface' => array('fooMethod', 'bazMethod'),
'CInterface' => array('barMethod')
);
extract(tad_DependencyMocker::on('ClassOne')
->forMethods(array('__construct', 'methodOne'))
->setExtraMethods($extraMethods)
->getMocksArray());
$A->expects($this->once())->method('method');
$BInterface->expects($this->once())->method('method');
$BInterface->expects($this->once())->method('fooMethod');
$BInterface->expects($this->once())->method('bazMethod');
$CInterface->expects($this->once())->method('method');
$CInterface->expects($this->once())->method('barMethod');
$D->expects($this->once())->method('method');
$sut = new ClassOne($D);
$sut->methodOne();
}
方法
该类定义以下方法
__construct($className, $methodNameOrArray, $extraMethods, $notation)
- 静态,基于指定的类返回类的实例;除了$className
之外,所有其他参数都可以稍后设置。on($className, $methodNameOrArray, $extraMethods, $notation)
- 静态,基于指定的类返回类的实例;除了$className
之外,所有其他参数都可以稍后设置。forMethods($methodNameOrArray)
- 设置类要模拟的方法或方法setNotation($notation)
- 设置用于从文档块中读取方法元信息的标记,默认标记为 "depends"。setExtraMethods($extraMethods)
- 设置一个数组,包含除了类已定义之外要存根的类/方法;在上面的示例中,BInterface
获取两个额外的存根方法,fooMethod
和bazMethod
它将不会实现。getMocks()
- 获取一个定义每个依赖项作为属性的stdClass
对象,该属性可通过属性 "->" 标记访问。getMocksArray()
- 获取一个包含每个模拟依赖项的键/值对的数组。