kenjis / monkey-patch
Monkey patching for exit(), functions, methods, and constants
Installs: 11 841
Dependents: 0
Suggesters: 0
Security: 0
Stars: 6
Watchers: 3
Forks: 2
Open Issues: 5
Requires
- php: ^7.3 || ^8.0
- ext-openssl: *
- ext-tokenizer: *
- nikic/php-parser: ^4.10
- phpunit/phpunit: ^9.5
Requires (Dev)
- bamarni/composer-bin-plugin: ^1.4
- kenjis/phpunit-helper: ^1.1
This package is auto-updated.
Last update: 2024-10-25 11:14:31 UTC
README
This package is a standalone package of ci-phpunit-test 's Monkey Patching.
This provides four monkey patchers.
ExitPatcher
: Convertsexit()
to ExceptionFunctionPatcher
: Patches FunctionsMethodPatcher
: Patches Methods in User-defined ClassesConstantPatcher
: Changes Constant Values
Table of Contents
Requirements
- PHP 7.3 or later
Installation
$ composer require --dev kenjis/monkey-patch
Usage
Note: The line number when an error occurs is probably different from the actual source code. Please check the cache file of the source that Monkey Patching creates.
Note: Using this package has a negative impact on speed of tests.
Configure
- To enable monkey patching, add the content of the bootstrap in your PHPUnit bootstrap file.
- Set MonkeyPatchManager::init() arguments.
- To verify invocations, use the MonkeyPatchTrait in your TestCase class.
Convert exit()
to Exception
This patcher converts exit()
or die()
statements to exceptions on the fly.
If you have a controller like below:
public function index() { $this->output ->set_status_header(200) ->set_content_type('application/json', 'utf-8') ->set_output(json_encode(['foo' => 'bar'])) ->_display(); exit(); }
A test case could be like this:
public function test_index() { try { $this->request('GET', 'welcome/index'); } catch (ExitException $e) { $output = ob_get_clean(); } $this->assertContains('{"foo":"bar"}', $output); }
Patch Functions
This patcher allows replacement of global functions that can't be mocked by PHPUnit.
But it has a few limitations. Some functions can't be replaced and it might cause errors.
So by default we can replace only a dozen pre-defined functions in FunctionPatcher.
public function test_index() { MonkeyPatch::patchFunction('mt_rand', 100, 'Welcome::index'); $output = $this->request('GET', 'welcome/index'); $this->assertContains('100', $output); }
MonkeyPatch::patchFunction()
replaces PHP native function mt_rand()
in Welcome::index
method, and it will return 100
in the test method.
Note: If you call MonkeyPatch::patchFunction()
without 3rd argument, all the functions (located in include_paths
and not in exclude_paths
) called in the test method will be replaced. So, for example, a function in your library code might be replaced, and it results in an unexpected outcome.
Change Return Value
You could change return value of patched function using PHP closure:
MonkeyPatch::patchFunction( 'function_exists', function ($function) { if ($function === 'random_bytes') { return true; } elseif ($function === 'openssl_random_pseudo_bytes') { return false; } elseif ($function === 'mcrypt_create_iv') { return false; } else { return __GO_TO_ORIG__; } }, Welcome::class );
Patch Other Functions
If you want to patch other functions, you can add them to functions_to_patch in MonkeyPatchManager::init()
.
But there are a few known limitations:
- Patched functions which have parameters called by reference don't work.
- You may see visibility errors if you pass non-public callbacks to patched functions. For example, you pass
[$this, 'method']
toarray_map()
and themethod()
method in the class is not public.
Patch Methods in User-defined Classes
This patcher allows replacement of methods in user-defined classes.
public function test_index() { MonkeyPatch::patchMethod( Category_model::class, ['get_category_list' => [(object) ['name' => 'Nothing']]] ); $output = $this->request('GET', 'welcome/index'); $this->assertContains('Nothing', $output); }
MonkeyPatch::patchMethod()
replaces get_category_list()
method in Category_model
, and it will return [(object) ['name' => 'Nothing']]
in the test method.
Patch Constants
This patcher allows replacement of constant value.
public function test_index() { MonkeyPatch::patchConstant( 'ENVIRONMENT', 'development', Welcome::class . '::index' ); $output = $this->request('GET', 'welcome/index'); $this->assertContains('development', $output); }
MonkeyPatch::patchConstant()
replaces the return value of the constant ENVIRONMENT
in Welcome::index
method.
There are a few known limitations:
- Cannot patch constants that are used as default values in function arguments.
- Cannot patch constants that are used as default values in constant declarations.
- Cannot patch constants that are used as default values in property declarations.
- Cannot patch constants that are used as default values in static variable declarations.
Class Reference
See ci-phpunit-test docs.
License
This package is licensed using the MIT License.
Please have a look at LICENSE
.