timacdonald / callable-fake
一个测试工具,允许您模拟和捕获可调用项/闭包的调用
v1.8.0
2024-05-18 07:32 UTC
Requires
- php: ^8.1
- phpunit/phpunit: ^10.0 || ^11.0
README
可调用/闭包测试模拟
如果您有一个公开API允许开发者传递闭包/可调用项,但不会产生内部或外部副作用(这些留给使用接口的开发者),则此包可能有助于测试。此类添加了一些命名断言,提供了一个非常受Laravel服务模拟启发的API。它可能稍微有点冗长,但它改变了测试的语言,使其更好地反映正在发生的事情。
它还使断言调用顺序以及可调用项被调用次数变得容易。
安装
您可以使用 composer 安装此包
composer require timacdonald/callable-fake --dev
基本用法
此包需要您测试特定类型的API/交互,才能发挥作用。想象一下您正在开发一个包,它包含以下接口...
interface DependencyRepository { public function each(callable $callback): void; }
此接口接受一个回调,并在底层遍历所有“依赖项”,并将每个依赖项传递给回调,以便开发者进行处理。
之前
让我们看看对这个方法的测试可能是什么样子...
public function testEachLoopsOverAllDependencies(): void { // arrange $received = []; $expected = factory(Dependency::class)->times(2)->create(); $repo = $this->app[DependencyRepository::class]; // act $repo->each(function (Dependency $dependency) use (&$received): void { $received[] = $dependency; }); // assert $this->assertCount(2, $received); $this->assertTrue($expected[0]->is($received[0])); $this->assertTrue($expected[1]->is($received[1])); }
之后
public function testEachLoopsOverAllDependencies(): void { // arrange $callable = new CallableFake(); $expected = factory(Dependency::class)->times(2)->create(); $repo = $this->app[DependencyRepository::class]; // act $repo->each($callable); // assert $callable->assertTimesInvoked(2); $callable->assertCalled(function (Depedency $dependency) use ($expected): bool { return $dependency->is($expected[0]); }); $callable->assertCalled(function (Dependency $dependency) use ($expected): bool { return $dependency->is($expected[1]); }); }
可用的断言
所有断言都是可链的。
assertCalled(callable $callback): self
$callable->assertCalled(function (Dependency $dependency): bool { return Str::startsWith($dependency->name, 'spatie/'); });
assertNotCalled(callable $callback): self
$callable->assertNotCalled(function (Dependency $dependency): bool { return Str::startsWith($dependency->name, 'timacdonald/'); });
assertCalledIndex(callable $callback, int|array $index): self
确保可调用项以显式顺序被调用,即作为第0次和第5次调用。
$callable->assertCalledIndex(function (Dependency $dependency): bool { return Str::startsWith($dependency, 'spatie/'); }, [0, 5]);
assertCalledTimes(callable $callback, int $times): self
$callable->assertCalledTimes(function (Dependency $dependency): bool { return Str::startsWith($dependency, 'spatie/'); }, 999);
assertTimesInvoked(int $times): self
$callable->assertTimesInvoked(2);
assertInvoked(): self
$callable->assertInvoked();
assertNotInvoked(): self
$callable->assertNotInvoked();
非断言API
asClosure(): Closure
如果方法使用 \Closure
而不是可调用项进行类型提示,则可以使用此方法将可调用项转换为 \Closure
实例。
$callable = new CallableFake; $thing->closureTypeHintedMethod($callable->asClosure()); $callable->assertInvoked();
wasInvoked(): bool
if ($callable->wasInvoked()) { // }
wasNotInvoked(): bool
if ($callable->wasNotInvoked()) { // }
called(callable $callback): array
$invocationArguments = $callable->called(function (Dependency $dependency): bool { return Str::startsWith($dependency->name, 'spatie/') });
指定返回值
如果您需要指定返回值,这可能表明这不是正确的工具。但是,在某些情况下,返回值决定了控制流,因此它可能很有用。在这种情况下,您可以将“返回解析器”传递给命名构造函数 withReturnResolver
。
$callable = CallableFake::withReturnResolver(function (Dependency $dependency): bool { if ($dependency->version === '*') { return '🤠'; } return '😀'; }); // You would not generally be calling this yourself, this is simply to demonstate // what will happen under the hood... $emoji = $callable(new Dependecy(['version' => '*'])); // $emoji === '🤠';
鸣谢
特别感谢 Caneco 为标志✨
感谢
您可以使用此包,但请与我联系,以联系某人(不是我自己)来感谢他们为您的项目中使用的开源库所做的贡献。请考虑您的整个技术堆栈:包、框架、语言、数据库、操作系统、前端、后端等。