idimsh / php-internals-mocker
帮助模拟PHP内部函数调用
Requires
- php: ~7.1
Requires (Dev)
- phpunit/phpunit: >=7.0 <8
- squizlabs/php_codesniffer: ^3.0
This package is auto-updated.
Last update: 2024-09-22 06:32:15 UTC
README
实用工具,允许在测试中模拟PHP内部函数调用。
安装
推荐的安装方法是使用Composer。运行以下命令安装最新版本的包并将其添加到项目的composer.json
中
composer require-dev idimsh/php-internals-mocker
使用方法
此模拟器旨在用于单元测试,假设一个类似以下的类
namespace Vendor\Namespace class MyClass { public function openConnction($hostname) { return fsockopen($hostname); } }
需要针对openConnction()
方法进行单元测试。一个PhpUnit测试用例可能是这样的
namespace VendorTest\Namespace class MyClassTest extends \PHPUnit\Framework\TestCase { public function testOpenConnction(): void { $object = new \Vendor\Namespace\MyClass; $hostname = \uniqid('hostname'); $actual = $object->openConnection($hostname); // ... } }
我们确实不想在单元测试中打开连接,因此这个模拟器可以避免调用原生的PHP fsockopen()
,并将其替换为对定义的回调的调用
namespace VendorTest\Namespace use idimsh\PhpInternalsMocker\PhpFunctionSimpleMocker; class MyClassTest extends \PHPUnit\Framework\TestCase { protected function setUp(): void { parent::setUp(); PhpFunctionSimpleMocker::reset(); } public function testOpenConnction(): void { $hostname = \uniqid('hostname'); $return = \uniqid('some mock for the return of fsockopen()'); PhpFunctionSimpleMocker::add( 'fsockopen', \Vendor\Namespace\MyClass::class, function ($inputHostname) use ($hostname, $return) { static::assertSame($inputHostname, $hostname); return $return; } ); $object = new \Vendor\Namespace\MyClass; $actual = $object->openConnection($hostname); static::assertSame($return, $actual); /** @noinspection PhpUnhandledExceptionInspection */ PhpFunctionSimpleMocker::phpUnitAssertNotEnoughCalls($this); } }
方法手册
1- PhpFunctionSimpleMocker::reset()
:应在PhpUnit TestCase 的 setUp()
方法或测试方法开始时调用。
2- PhpFunctionSimpleMocker::add()
:在调用 reset()
之后调用,以注册预期调用原生函数的回调,签名
/** * Register a call back to be called for the PHP internal function which is to be used in the class passed. * * If the $callback is null, then this PHP function is not expected to be called. * * Assertions can be done inside the callback. * * @param string $internalFunctionName The PHP function name to mock * @param string $beingCalledFromClass The class FQN which calls $internalFunctionName * @param callable|null $callback * @param int $numberOfCalls To mock more than once for the same callback, pass the number here */ public static function add( string $internalFunctionName, string $beingCalledFromClass, ?callable $callback, int $numberOfCalls = 1 ): void
它可以多次使用相同的 $internalFunctionName
和不同的 $callback
调用,顺序与预期相同。$beingCalledFromClass
预期一个类的FQN,从这个命名空间中提取出来,并将函数注册在该命名空间。
3- PhpFunctionSimpleMocker::phpUnitAssertNotEnoughCalls($testCase)
:在PhpUnit测试方法中所有断言注册完毕后(最后一行)调用,此方法将确保达到最小调用次数。
4- PhpFunctionSimpleMocker::assertPostConditions(?$testCase)
:是 PhpFunctionSimpleMocker::phpUnitAssertNotEnoughCalls($testCase)
的替代方法,并应从 PhpUnit TestCase 方法中调用:assertPostConditions()
,而不是在每个测试方法结束时调用前一个方法,只需要一个调用传递 TestCase 就足够断言最小计数。
使用条件
要模拟并替换为回调的原生PHP函数调用需要(所有都必须适用)
- 从类方法或定义在命名空间内的函数中调用,而不是从全局命名空间中的类方法或函数中调用。
- PHP原生函数的调用之前不能有全局命名空间解析运算符 '\'
- 在类中不使用
use function
语句导入该原生函数到命名空间。
限制
快速
- 目前不支持使用引用的PHP原生函数,但计划支持。
- 在PhpUnit中,必须显式处理调用次数不足的断言,通过调用
PhpFunctionSimpleMocker::phpUnitAssertNotEnoughCalls($this)
或PhpFunctionSimpleMocker::assertPostConditions($this)
,如果有更好的想法,请分享。 - 对于任何奇怪的问题,PhpUnit的
@runInSeparateProcess
选项可能有所帮助,尽管我尚未遇到此类情况,请报告任何问题。
致谢
- Abdulrahman Dimashki
- 所有贡献者
- 一个旧的 Symfony 类,用于模拟PHP内部函数,无法找到其源代码。但
PhpFunctionSimpleMocker::register()
中的代码是从它那里取出的。
替代方案
有一个我尚未测试的解决方案 php-mock
许可证
在MIT许可证下发布 - 详细内容请参阅许可证文件。