olvlvl/phpunit-given
Composer 安装命令:
composer require olvlvl/phpunit-given
包简介
An alternative to PHPUnit's ReturnValueMap and ReturnCallback. A convenient solution to migrate from Prophecy.
关键字:
README 文档
README
olvlvl/phpunit-given provides an alternative to PHPUnit's ReturnValueMap and ReturnCallback, as well as a convenient solution to migrate from Prophecy.
Disclaimer
In most cases ReturnCallback with match can be used effectively. Don't use this package if you're comfortable with these and don't need extra features.
$mock = $this->createMock(IntegerName::class); $mock->method('name')->willReturnCallback(fn (Integer $int) => match (true) { $int < new Integer(6) => 'too small', $int > new Integer(9) => 'too big', default => 'just right'; }));
$mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this ->given(Assert::lessThan(new Integer(6)))->return('too small') ->given(Assert::greaterThan(new Integer(9)))->return('too big') ->default()->return('just right') );
Usage
This is a simple example, more use cases below.
use olvlvl\Given\GivenTrait; use PHPUnit\Framework\TestCase; final class IntegerNameTest extends TestCase { use GivenTrait; // <-- adds the method 'given' public function testName(): void { $mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this ->given(new Integer(6))->return("six") ->given(new Integer(12))->return("twelve") ->default()->throw(LogicException::class) ); $this->assertEquals("six", $mock->name(new Integer(6))); $this->assertEquals("twelve", $mock->name(new Integer(12))); $this->expectException(LogicException::class); $mock->name(new Integer(99)); } }
Installation
composer require olvlvl/phpunit-given
Motivation
Coming from Prophecy, C# Moq, Golang Mock, or Kotlin Mockk, one would expect at least one of the following examples to work, but they do not.
$mock = $this->createMock(IntegerName::class); $mock ->method('name') ->with(new Integer(6)) ->willReturn("six"); $mock ->method('name') ->with(new Integer(12)) ->willReturn("twelve"); // the next line crashes with: Expectation failed $this->assertEquals("six", $mock->name(new Integer(6)));
$mock = $this->createMock(IntegerName::class); $mock ->method('name') ->with(new Integer(6))->willReturn("six"); // the next line crashes with: Method parameters already configured ->with(new Integer(12))->willReturn("twelve"); $this->assertEquals("six", $mock->name(new Integer(6)));
To return a value given certain arguments, one is expected to use ReturnValueMap or ReturnCallback. ReturnValueMap seems simple enough, but because it looks for exact matches it fails when objects are included in the arguments, unless they are the same instances. Besides, ReturnValueMap does not support constraints, you can forget doing anything fancy with it. That leaves us with ReturnCallback, which can be used effectively with match but requires the introduction of logic in the test, a practice that is discouraged.
$mock = $this->createMock(IntegerName::class); $mock->method('name')->willReturnCallback(fn (Integer $int) => match ($int) { new Integer(6) => 'six', new Integer(12) => 'twelve', default => throw new Exception }));
My motivation for creating olvlvl/phpunit-given, is to have an alternative to ReturnValueMap and ReturnCallback, that looks similar to what we find in other testing frameworks, and that allows easy migration from Prophecy.
Some PHPUnit issues, for reference:
- Feature similar to withConsecutive(), but without checking order
- Improvements on withConsecutive with return
- Remove withConsecutive()
- Symphony: Remove occurrences of withConsecutive()
Use cases
Comparing with objects
ReturnValueMap doesn't work with objects because it uses strict equality when comparing
arguments. The following code throws a TypeError exception because ReturnValueMap cannot find a match and defaults to a null value.
$mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this->returnValueMap([ [ new Integer(6), "six" ], [ new Integer(12), "twelve" ], ])); $mock->name(new Integer(6)); // throws TypeError
olvlvl/phpunit-given substitutes values with Assert::equalTo() and compares arguments using constraints. Having objects in the arguments is not a problem.
$mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this ->given(new Integer(6))->return("six") ->given(new Integer(12))->return("twelve") ); $this->assertEquals("six", $mock->name(new Integer(6))); $this->assertEquals("twelve", $mock->name(new Integer(12)));
Note: You can use Assert::identicalTo() to check for the same instance.
Using constraints
We established that values are substituted with Assert::equalTo() internally. Instead of values, you can also use constraints:
$mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this ->given(Assert::lessThan(new Integer(6)))->return('too small') ->given(Assert::greaterThan(new Integer(9)))->return('too big') ->default()->return('just right') ); $this->assertEquals("too small", $mock->name(new Integer(5))); $this->assertEquals("too big", $mock->name(new Integer(10))); $this->assertEquals("just right", $mock->name(new Integer(6))); $this->assertEquals("just right", $mock->name(new Integer(9)));
Migrating from Prophecy
olvlvl/phpunit-given is a convenient solution to migrate from Prophecy because the code is quite similar:
$container = $this->prophesize(ContainerInterface::class); $container->has('serviceA')->willReturn(true); $container->has('serviceB')->willReturn(false);
$container = $this->createMock(ContainerInterface::class); $container->method('has')->will($this ->given('serviceA')->return(true) ->given('serviceB')->return(false) );
throw() is an alternative to willThrow(), and you can mismatch return() and throw():
$container = $this->prophesize(ContainerInterface::class); $container->get('serviceA')->willReturn($serviceA); $container->get('serviceB')->willThrow(new LogicException());
$container = $this->createMock(ContainerInterface::class); $container->method('get')->will($this ->given('serviceA')->return($serviceA) ->given('serviceB')->throw(LogicException::class) );
Contrary to Prophecy, olvlvl/phpunit-given does not return null by default, instead it throws an exception:
$mock = $this->createMock(IntegerName::class); $mock->method('name')->will($this ->given(new Integer(6))->return("six") ->given(new Integer(12))->return("twelve") ); $mock->name(new Integer(13)); // throws an exception
LogicException : Unexpected invocation: Test\olvlvl\Given\Acme\IntegerName::name(Test\olvlvl\Given\Acme\Integer Object (...)): string, didn't match any of the constraints: [ [ is equal to Test\olvlvl\Given\Acme\Integer Object &000000000000000c0000000000000000 (
'value' => 6
) ], [ is equal to Test\olvlvl\Given\Acme\Integer Object &00000000000001af0000000000000000 (
'value' => 12
) ] ]
Continuous Integration
The project is continuously tested by GitHub actions.
Code of Conduct
This project adheres to a Contributor Code of Conduct. By participating in this project and its community, you're expected to uphold this code.
Contributing
See CONTRIBUTING for details.
License
olvlvl/phpunit-given is released under the BSD-3-Clause.
olvlvl/phpunit-given 适用场景与选型建议
olvlvl/phpunit-given 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 49 次下载、GitHub Stars 达 1, 最近一次更新时间为 2023 年 02 月 05 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「phpunit」 「mock」 「test double」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 olvlvl/phpunit-given 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 olvlvl/phpunit-given 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 olvlvl/phpunit-given 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
LazyPDO is a set of wrappers over PHP's standard PDO and PDOStatement classes. It enables lazy loading, serialization and decoration.
HiDev plugin for PHPUnit
Testing Suite For Lumen like Laravel does.
A cli tool which generates unit tests.
Mock PSR-18 HTTP client
Specification-oriented BDD helpers for PHPUnit
统计信息
- 总下载量: 49
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 17
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: BSD-3-Clause
- 更新时间: 2023-02-05