dancras / doubles
测试双倍框架
Requires
- php: >=5.3.0
This package is not auto-updated.
Last update: 2024-09-14 13:18:05 UTC
README
Doubles是一个php测试双倍库,旨在提供简单、逻辑化的API以及编写单元测试时的语法糖。它特别适合单元测试中的arrange-act-assert模式,尽管它并不刻意强加任何风格。它是为phpunit设计的,但没有依赖项,也可以与其他测试框架一起使用。它目前处于早期开发阶段,任何反馈都非常欢迎。
需要PHP 5.3以上。
不需要对单元测试框架进行任何更改即可集成。
版权(c)2012 Daniel Howlett
双重许可下MIT和GPL许可证。
反馈可以在http://www.dancras.co.uk留下
使用composer安装
要从packagist安装,请将以下内容添加到您的composer.json文件中
{
"minimum-stability": "dev",
"require": {
"dancras/doubles": "*"
}
}
别忘了将vendor/autoload.php包含在您的代码中。
已知问题
-
如果您的类有与所选测试双倍相匹配的方法,目前没有方法可以访问测试双倍方法。
-
由库触发的失败将以E代码而不是F代码在phpunit中失败测试。
-
目前不支持PHP 5.4功能,例如“callable”类型提示。
参考
添加以下内容
use Doubles\Doubles;
完整测试双倍
用主题的所有方法创建测试双倍
$double = Doubles::fromClass('\MyClass');
$double = Doubles::fromInterface('\MyInterface');
如果主题不存在,Doubles将创建主题。
部分测试双倍
部分测试双倍的方法在它们被存根、模拟或拦截之前不受影响。它们从一个主题实例中创建。
$subject = new \Doubles\Test\Dummy;
$double = Doubles::partial($subject);
可能需要跳过主题的构造函数
$subject = Doubles::noConstruct('\Doubles\Test\Dummy');
间谍
提供对测试双倍交互历史的访问,包括部分测试双倍未受影响的方法。一个图形服务测试双倍可能执行以下操作
$double->plot(0, 5);
$double->plot(2, 6);
$double->setLineColour('red');
$double->render();
代码运行后,我们可以调查测试双倍
$double->spy('plot')->args(0); // array(0, 5)
$double->spy('plot')->args(); // array(array(0, 5), array(2, 6))
$double->spy('plot')->findArgs(2, 6); // 1
$double->spy('plot')->arg(1, 0); // 2
$double->spy('plot')->callCount(); // 2
$double->callCount(); // 4
一次调用
当方法期望一次调用时,我们可以使用一次调用变体来避免多余的断言。注意,在一次性变体中使用时,可以省略调用索引。
$double->spy('setLineColour')->oneCallArgs(); // array('red')
$double->spy('setLineColour')->oneCallArgs(0); // 'red'
如果方法没有收到正好一次调用,一次性方法将抛出异常。
$double->spy('plot')->oneCallArgs(); // throws \Doubles\Core\FailureException
$double->spy('foo')->oneCallArgs(); // throws \Doubles\Core\FailureException
调用顺序
从一开始。可以用来断言方法以预期的顺序被调用。
$double->spy('plot')->callOrder(0); // 1
$double->spy('plot')->callOrder(1); // 2
一次性变体也适用于调用顺序
$double->spy('render')->oneCallOrder(0); // 4
以下代码断言render最后只调用一次
$this->assertSame(
$double->callCount(),
$double->spy('render')->oneCallOrder(0)
); // pass
共享调用顺序
有时需要比较实例之间的调用顺序。Doubles\Spy\CallCounter::shareNew()方法分发一个共享调用计数器。假设本例中的所有对象都已作为测试双倍创建
use Doubles\Spy\CallCounter;
CallCounter::shareNew($pizza, $waiter, $customer);
以下操作被错误地执行在我们的对象上。我们的不耐烦的客户似乎在帮助他自己
$pizza->cook();
$customer->eat($pizza);
$waiter->take($pizza);
使用共享调用顺序,我们可以在测试中捕获这个错误。披萨必须在服务员取之前烹饪
$this->assertGreaterThan(
$pizza->spy('cook')->oneSharedCallOrder(),
$waiter->spy('take')->sharedCallOrder(0)
); // pass
服务员必须在接受披萨之前取披萨
$this->assertGreaterThan(
$waiter->spy('take')->sharedCallOrder(0),
$customer->spy('eat')->sharedCallOrder(0)
); // fail
再次注意一次性变体,确保我们的披萨不会烧焦。
存根
$double->stub('foo', 'bar');
$double->foo(); // 'bar'
我们可以同时存根多个方法,例如,存根流畅接口
$double->stub('setX', 'setY', $double);
$double->setX(); // $double
$double->setY(); // $double
存根也可以抛出异常
$double->stub('boom', new EndOfTheWorldException);
$double->boom(); // throws EndOfTheWorldException
要实际返回一个异常,您需要使用模拟。
模拟
模拟是测试方法的最高效方式,但可能难以理解。
$myObject->mock('give', function ($methodName, $arguments) use (&$m, &$a) {
$m = $methodName; // 'give'
$a = $arguments; // array(1, 2, 3)
return 'result';
});
$myObject->give(1, 2, 3); // 'result'
不建议在模拟回调中执行断言。如果您的代码未能调用该方法,则不会执行任何断言,测试可能会通过。
如果您在模拟中执行断言,可能想要使用间谍对象。或者,通过引用使用变量将允许您在闭包外部执行断言。
拦截器
拦截是一种改进的模拟形式,可用于部分对象,提供部分主题的实例给回调。
$myObject->intercept('foo', function ($methodName, $arguments, $instance) use (&$m, &$a) {
$m = $methodName; // 'foo'
$a = $arguments; // array(1, 2, 3)
return $instances->foo($a);
});
$myObject->give(1, 2, 3); // 'result'
期望
当您模拟或存根一个方法时,它就变成了期望。默认情况下,对未期望的方法的调用没有影响。
$myObject->unknown(); // null
$myObject->setUnexpectedMethodCallback(function ($methodName, $arguments) {
throw new Exception;
});
$myObject->unknown(); // throws Exception
快速原型设计
默认情况下,当使用测试替身(test double)对一个已定义类型进行测试时,如果调用了一个原始类或测试替身API上不存在的方法,则会抛出异常。
如果该类型不存在,则被认为是快速原型设计(因为必须事先定义所有类签名变得繁琐)。在此模式下,可以使用任何方法。当您定义类或接口时,测试将失败,直到您完成其签名。
我发现这种行为非常有效,但如果这不是期望的功能,则可以强制启用快速原型设计模式,这意味着可以在类或接口签名之外自由使用方法。
\Doubles\Core\TestDouble::$isRapidPrototypingEnabled = true;