facile-it / moka
创建模拟对象的简写
Requires
- php: ^7.1
- phpcollection/phpcollection: ^0.5
- phpunit/phpunit: ^7.0
- psr/container: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16
- mockery/mockery: ^1.0
- phake/phake: ^3.0
- phpspec/prophecy: ^1.7
- phpstan/phpstan: ^0.12.8
Suggests
- facile-it/paraunit: For parallel test running; it's fast!
- mockery/mockery: To allow loading of MockeryPlugin
- phake/phake: To allow loading of PhakePlugin
- phpspec/prophecy: To allow loading of ProphecyPlugin
This package is auto-updated.
Last update: 2024-09-18 21:05:33 UTC
README
厌倦了把大部分测试时间花在无休止地模拟对象上? 是的。
Moka 提供两种简单方法来减少你在这种繁琐任务上的工作量,并且通过一个令人难以置信的抽象层在最受欢迎的模拟引擎和 你 之间。
安装
您可以通过 composer 安装此包
composer require --dev facile-it/moka
用法
要在测试中使用 Moka,只需使用函数 Moka\Plugin\PHPUnit\moka()
(见下方的生成器部分)并运行 Moka::clean()
以在每个测试之前。一个简单的接口将允许你创建 moka(模拟)对象,并通过流畅的接口用 stub 方法属性装饰它们
<?php namespace Foo\Tests; use Moka\Moka; use function Moka\Plugin\PHPUnit\moka; class FooTest extends \AnyTestCase { private $foo; protected function setUp(): void { Moka::clean(); // The subject of the test. $this->foo = new Foo( moka(BarInterface::class)->stub([ // Property name => value. '$property' => 3, // Method name => return value. 'method1' => moka(AcmeInterface::class), 'method2' => true ]) ); } //... }
或者,你可以直接调用 Moka::phpunit(string $fqcnOrAlias, string $alias = null): ProxyInterface
,而不是使用 moka()
。
作为一个如此简单的项目,Moka 可以轻松集成到现有的测试套件中。
注意:如果您正在扩展 PHPUnit TestCase
,为了简化清理阶段,我们提供了一个 MokaCleanerTrait
,它会在每个测试之后自动运行 Moka::clean()
。
<?php namespace Foo\Tests; use Moka\Traits\MokaCleanerTrait; use PHPUnit\Framework\TestCase; use function Moka\Plugin\PHPUnit\moka; class FooTest extends TestCase { use MokaCleanerTrait; protected function setUp(): void { // No call to Moka::clean() needed. // ... } // ... }
您可以根据下面的示例依赖原始模拟对象实现(在下面的示例中,PHPUnit 的 - 对于 Prophecy 见下文)
<?php moka(BarInterface::class, 'bar') ->expects($this->at(0)) ->method('isValid') ->willReturn(true); moka('bar') ->expects($this->at(1)) ->method('isValid') ->willThrowException(new \Exception()); var_dump(moka('bar')->isValid()); // bool(true) var_dump(moka('bar')->isValid()); // throws \Exception
参考
moka(string $fqcnOrAlias, string $alias = null): ProxyInterface
创建一个包含模拟对象(根据所选策略)的代理,用于提供的 FQCN,并且可以选择性地分配一个 $alias
来在以后获取它
<?php $mock1 = moka(FooInterface::class); // Creates the mock for FooInterface. $mock2 = moka(FooInterface::class); // Gets a different mock. var_dump($mock1 === $mock2); // bool(false)
$alias
允许您存储模拟实例
<?php $mock1 = moka(FooInterface::class, 'foo'); // Creates a mock for FooInterface. $mock2 = moka('foo'); // Get the mock previously created. var_dump($mock1 === $mock2); // bool(true)
ProxyInterface::stub(array $namesWithValues): ProxyInterface
接受一个方法或属性 stubs 的数组,格式为 [$name => $value]
,其中 $name
必须 是一个字符串,$value
可以是任何类型,包括另一个模拟对象。
注意:
- 属性通过在其名称前加符号
$
来标识 - 当调用方法时,将抛出异常实例作为方法值
<?php $mock = moka(BarInterface::class)->stub([ '$property' => 1, 'isValid' => true, 'getMock' => moka(AcmeInterface::class), 'throwException' => new \Exception() ]); var_dump($mock->property); // int(1) var_dump($mock->isValid()); // bool(true)
注意:方法 stubs 对定义的任何方法调用都有效,并且不能被覆盖。
如果您需要更细粒度的调用策略控制,您可以通过 获取原始模拟对象实现。
支持的模拟对象生成器
目前我们与内置支持 PHPUnit 模拟对象。
我们还支持其他生成器,但您需要安装相关包才能使其工作
我们为每个支持的策略提供了一个特定的 moka()
函数,以及一个静态方法(方法本身有文档说明)
Moka\Plugin\PHPUnit\moka
Moka\Plugin\Prophecy\moka
Moka\Plugin\Mockery\moka
Moka\Plugin\Phake\moka
Prophecy 本地行为
Prophecy 允许您通过直接在 ObjectProphecy
上调用方法来模拟方法。 Moka 不支持这种行为,但提供了一个简单的解决方案
<?php // Native Prophecy behavior... $this->prophesize(FooInterface::class) ->someMethod(new AnyValuesToken()) ->willReturn($something); // ...translates to... Moka::prophecy(FooInterface::class) ->someMethod->set(new AnyValuesToken()) ->willReturn($something);
注意:此解决方案不能用于与之前模拟的属性同名的函数
<?php Moka::prophecy(FooInterface::class, 'foo')->stub([ '$someName' => true ]); var_dump(Moka::prophecy('foo')->someName); // bool(true) Moka::prophecy('foo') ->someName->set(new AnyValuesToken()) ->willReturn($something); // throws \Exception
插件开发
如果您觉得自己很聪明,想要创建自己的模拟生成器(或添加对现有生成器的支持),只需实现 Moka\Plugin\PluginInterface
以及相关的 Moka\Strategy\MockingStrategyInterface
<?php namespace Moka\Plugin\YourOwn; use Moka\Plugin\PluginInterface; use Moka\Strategy\MockingStrategyInterface; class YourOwnPlugin implements PluginInterface { public static function getStrategy(): MockingStrategyInterface { return new YourOwnMockingStrategy(); } }
通过扩展 AbstractMockingStrategy
来实现您策略的更简单(和更严格)的实现
<?php namespace Moka\Plugin\YourOwn; use Moka\Strategy\AbstractMockingStrategy; use Moka\Stub\MethodStub; class YourOwnMockingStrategy extends AbstractMockingStrategy { public function __construct() { // TODO: Implement __construct() method. } protected function doBuild(string $fqcn) { // TODO: Implement doBuild() method. } protected function doDecorateWithMethod($mock, MethodStub $stub) { // TODO: Implement doDecorateWithMethod() method. } protected function doGet($mock) { // TODO: Implement doGet() method. } protected function doCall($mock, string $methodName) { // Override doCall() if you need special behavior. // See ProphecyMockingStrategy::doCall(). } }
注意:您的插件 FQCN 必须与模板 Moka\Plugin\YourOwn\YourOwnPlugin
匹配,其中 YourOwn
是插件名称。
您的插件和策略都必须通过我们的测试用例(请安装 phpunit/phpunit 来运行它们)
MokaPluginTestCase
MokaMockingStrategyTestCase
让我们知道任何与 Moka 相关的开发!
测试
我们强烈建议使用 Paraunit 来加快测试执行速度
composer global require facile-it/paraunit paraunit run
致谢
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件