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
- PHP 7.3 or later
$ composer require --dev kenjis/monkey-patch
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.
- 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.
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);
}
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.
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
);
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.
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.
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.
See ci-phpunit-test docs.
This package is licensed using the MIT License.
Please have a look at LICENSE
.