jeremeamia / func-mocker
允许您覆盖命名空间内使用的全局函数,以进行测试目的。
0.1.0
2016-03-15 04:25 UTC
Requires
- php: ~5.6|~7.0
Requires (Dev)
- phpunit/phpunit: 4.*|5.*
- squizlabs/php_codesniffer: ~2.3
This package is auto-updated.
Last update: 2024-09-20 11:53:42 UTC
README
FuncMocker – 像朋克摇滚一样模拟PHP函数?
允许您覆盖(即模拟)在特定命名空间内使用的全局函数,以进行测试。
我为以下两个主要用例开发了此功能
- 当您正在测试调用非确定性函数的对象(如
time()
和rand()
),并且需要这些函数返回确定性值以进行测试时。 - 当您正在处理必须调用函数的对象的代码。这在以前不是面向对象的遗留代码库中很常见。例如,如果您的项目中有一个名为
db_add()
的函数,您最终在模型层中使用该对象,您可能希望在测试时“模拟”该函数,以便您实际上不需要在单元测试中调用数据库。
此代码背后的简单技术在此Fabian Schmengler的博客文章中进行了描述。基本上,它涉及利用PHP的命名空间解析规则。
安装
通过Composer
$ composer require jeremeamia/func-mocker
用法
假设您有一个在命名空间My\App
中定义的RandomNumberGenerator
类,它调用全局函数rand()
。您可以使用FuncMocker
覆盖该特定命名空间中rand()
的使用。
use My\App\RandomNumberGenerator; use FuncMocker\Mocker; Mocker::mock('rand', 'My\App', function () { return 5; }); $rng = new RandomNumberGenerator(1, 10); echo $rng->getNumber(); //> 5 echo $rng->getNumber(); //> 5 echo $rng->getNumber(); //> 5
更长的例子
假设有一个使用全局函数(例如time()
)的类,您想对其进行模拟。
<?php namespace My\Crypto; use Psr\Http\Message\RequestInterface as Request; class Signer { // ... public function getStringToSign(Request $request) { return $request->getMethod() . "\n" . time() . "\n" . $request->getHeader('X-API-Operation')[0] . "\n" . $request->getBody(); } // ... }
以下是一个使用FuncMocker
将time()
模拟为返回固定值的PHPUnit测试示例,这使得编写测试变得容易得多。
<?php namespace My\App\Tests; use FuncMocker\Mocker as FuncMocker; use My\Crypto\Signer; use Psr\Http\Message\RequestInterface as Request; class SignerTest extends \PHPUnit_Framework_TestCase { // ... public function testCanGetStringToSign() { // Mock the request with PHPUnit $request = $this->getMock(Request::class); $request->method('getMethod')->willReturn('POST'); $request->method('getHeader')->willReturn(['CREATE_THING']); $request->method('getBody')->willReturn('PARAMS'); // Mock the call to PHP's time() function to give us a deterministic value. FuncMocker::mock('time', 'My\Crypto', function () { return 12345; }); $signer = new Signer(); // Check to see that the string to sign is constructed how we would expect. $this->assertEquals( "POST\n12345\nCREATE_THING\nPARAMS", $signer->getStringToSign() ); } // ... }
禁用和重新启用
FuncMocker还允许您禁用您设置的模拟,以防您需要在某些测试中使用函数的正常行为。
$func = FuncMocker\Mocker::mock('time()', 'My\App', function () { return 1234567890; }); echo My\App\time(); //> 1234567890 $func->disable(); echo My\App\time(); //> 1458018866 $func->enable(); echo My\App\time(); // > 1234567890
限制
- 要模拟的函数必须在使用全局命名空间之外的命名空间中使用。
- 要模拟的函数不得使用完全限定名进行引用(例如,
\time()
)。
测试
$ composer test
致谢
- Jeremy Lindblom - 主要作者。
- Marius Sarca - 从opis/closure借用了他的流包装器包含技术。
替代方案
- 自行完成。请参阅以下文章
- php-mock/php-mock - 我之后找到的类似功能模拟库。
- Patchwork - 更健壮的模拟库,可以拦截对函数的调用。
- Atoum - 具有内置函数模拟功能的全功能测试框架。
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。