lucatume / function-mocker-le
轻量级的函数模拟解决方案。
Requires
- php: >=5.4
Requires (Dev)
- phpunit/phpunit: ^6.3
This package is auto-updated.
Last update: 2024-09-07 20:49:40 UTC
README
当function-mocker过于强大时。
代码示例
<?php use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Assert; use function tad\FunctionMockerLe\define; use function tad\FunctionMockerLe\defineWithMap; use function tad\FunctionMockerLe\defineWithValueMap; use function tad\FunctionMockerLe\defineAll; use function tad\FunctionMockerLe\undefineAll; class MyOrmTest extends TestCase { public function test_query_parameters_are_preserved(){ // define a non existing function define('get_posts', function(array $args){ Assert::assertEquals(['post_type' => 'book','paginated' => 2, 'posts_per_page' => 6], $args); return []; }); $orm = new MyOrm('book'); $orm->query() ->page(2) ->perPage(6) ->fetch(); } public function test_users_cannot_fetch_posts_they_cannot_read(){ // define a number of functions using a <function> => <callback> map defineWithMap([ 'is_user_logged_in' => function(){ return true; }, 'get_posts' => function(){ return[ ['ID' => 1, 'post_title' => 'One'], ['ID' => 2, 'post_title' => 'Two'], ['ID' => 3, 'post_title' => 'Three'], ['ID' => 4, 'post_title' => 'Four'] ]; }, 'current_user_can' => function($cap, $id){ // a post ID to 'can' map $map = [ 1 => true, 2 => true, 3 => false, 4 => true ]; return $map($id); } ]); $orm = new MyOrm('book'); $books = $orm->query() ->fetch(); $expected = [ ['ID' => 1, 'post_title' => 'One'], ['ID' => 2, 'post_title' => 'Two'], ['ID' => 4, 'post_title' => 'Four'] ]; $this->assertEquals($expected, $books); } public function test_sticky_posts_are_not_prepended_if_not_home_archive_or_tag(){ // define a number of functions all with the same callback... defineAll(['is_home', 'is_archive', 'is_tag'], function(){ return false; }); define('get_posts', function(array $args){ Assert::arrayHasKey('ignore_sticky_posts,', $args); Assert::assertEquals('1', $args['ignore_sticky_posts']); }); $orm = new MyOrm('book'); $orm->query()->fetch(); // ...and then redefine them defineWithValueMap([ 'is_home' => true, 'is_archive' => false, 'is_tag' => false ]); // redefine as needed define('get_posts', function(array $args){ Assert::arrayNotHasKey('ignore_sticky_posts,', $args); }); $orm->query()->fetch(); } public function tearDown() { // undefine all the functions after each test to avoid test dependencies undefineAll(); } }
安装
使用Composer在项目中引入库
composer require --dev lucatume/function-mocker-le
为什么需要模拟函数?这解决了什么问题?
该库提供了一个轻量级且无依赖的函数模拟解决方案。
在测试中可能需要模拟函数的原因是测试任何依赖于基于函数的框架(例如 WordPress)的代码。
与function-mocker相比,此库仅在定义的函数在执行期间都没有定义时才会工作;function-mocker将允许在运行时对已定义的函数进行猴子补丁。
当函数模拟器依赖于Patchwork库来允许用户在本地进行猴子补丁时,此库具有最小的代码足迹,并且仅提供少量函数。
如果真的不能避免在测试中加载模拟函数的源代码,应使用Patchwork或function-mocker。
使用方法
库的核心功能是define($function, $callback)
:它定义一个函数并将其内容设置为回调;在其基本用法中,它允许在测试中设置模拟函数的返回值
public function test_current_user_can(){ tad\FunctionMockerLe\define('current_user_can', function(){ return true; }); $this->assertTrue(current_user_can('read_posts')); }
$callback
参数可以是任何类型的callable
,在这个例子中,我使用Prophecy模拟引擎来设置复杂的期望
public function test_prophecy(){ $pr = $this->prophesize(User::class); $pr->can('read_posts')->shouldBeCalled(); $pr->can('edit_posts')->shouldNotBeCalled(); tad\FunctionMockerLe\define('current_user_can', [$pr->reveal(), 'can']); current_user_can('read_posts'); current_user_can('edit_posts'); // this will trigger a failure: not expected current_user_can('read_posts'); }
还可以依赖PhpUnit库提供的基本断言
public function test_prophecy(){ tad\FunctionMockerLe\define('current_user_can', function($cap){ PHPUnit\Framework\Assert::assertNotEquals('edit_posts', $cap); }); current_user_can('read_posts'); current_user_can('edit_posts'); // this will trigger a failure: not expected current_user_can('read_posts'); }
当function-mocker试图提供针对模拟函数(及更多)问题的功能丰富解决方案时,此项目试图提供一个不带任何偏见的选择的基本起点。
库提供的其他功能只是围绕define
核心的糖包装;请参阅示例和/tests
文件夹以获得清晰度。undefine($function)
和undefineAll()
方法将“取消定义”由Function Mocker LE库管理的函数;在这种情况下,“取消定义”意味着调用未定义的函数将抛出tad\FunctionMockerLe\UndefinedFunctionException
。
测试
要运行测试,请安装Composer依赖项并运行PHPUnit
composer install vendor/bin/phpunit