{"id":15306915,"url":"https://github.com/kenjis/monkey-patch","last_synced_at":"2025-04-15T00:54:50.800Z","repository":{"id":48686626,"uuid":"344426372","full_name":"kenjis/monkey-patch","owner":"kenjis","description":"Standalone package of ci-phpunit-test's Monkey Patching.","archived":false,"fork":false,"pushed_at":"2024-07-11T07:19:18.000Z","size":190,"stargazers_count":6,"open_issues_count":6,"forks_count":2,"subscribers_count":2,"default_branch":"1.x","last_synced_at":"2025-04-15T00:54:46.264Z","etag":null,"topics":["hacktoberfest","monkey-patch","monkey-patching","phpunit","testing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kenjis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-04T09:55:25.000Z","updated_at":"2024-10-11T06:50:24.000Z","dependencies_parsed_at":"2022-07-25T01:02:33.990Z","dependency_job_id":null,"html_url":"https://github.com/kenjis/monkey-patch","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjis%2Fmonkey-patch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjis%2Fmonkey-patch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjis%2Fmonkey-patch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenjis%2Fmonkey-patch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenjis","download_url":"https://codeload.github.com/kenjis/monkey-patch/tar.gz/refs/heads/1.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248986279,"owners_count":21194025,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","monkey-patch","monkey-patching","phpunit","testing"],"created_at":"2024-10-01T08:08:24.735Z","updated_at":"2025-04-15T00:54:50.782Z","avatar_url":"https://github.com/kenjis.png","language":"PHP","readme":"# Monkey Patch\n\nThis package is a standalone package of [ci-phpunit-test](https://github.com/kenjis/ci-phpunit-test) 's Monkey Patching.\n\nThis provides four monkey patchers.\n\n- `ExitPatcher`: Converts `exit()` to Exception\n- `FunctionPatcher`: Patches Functions\n- `MethodPatcher`: Patches Methods in User-defined Classes\n- `ConstantPatcher`: Changes Constant Values\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Configure](#configure)\n  - [Convert `exit()` to Exception](#convert-exit-to-exception)\n  - [Patch Functions](#patch-functions)\n    - [Change Return Value](#change-return-value)\n    - [Patch Other Functions](#patch-other-functions)\n  - [Patch Methods in User-defined Classes](#patch-methods-in-user-defined-classes)\n  - [Patch Constants](#patch-constants)\n- [Class Reference](#class-reference)\n- [License](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Requirements\n\n- PHP 7.3 or later\n\n## Installation\n\n```sh-session\n$ composer require --dev kenjis/monkey-patch\n```\n\n## Usage\n\n**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.\n\n**Note:** Using this package has a negative impact on speed of tests.\n\n### Configure\n\n- To enable monkey patching, add [the content of the bootstrap](https://github.com/kenjis/monkey-patch/blob/1.x/src/bootstrap.php) in your PHPUnit bootstrap file.\n  - Set [MonkeyPatchManager::init()](https://github.com/kenjis/monkey-patch/blob/f5b1839a01c0c3cd56f4873e8c307b0583a5526b/src/bootstrap.php#L31-L61) arguments.\n- To verify invocations, use the [MonkeyPatchTrait](https://github.com/kenjis/monkey-patch/blob/1.x/src/Traits/MonkeyPatchTrait.php) in your TestCase class.\n\n### Convert `exit()` to Exception\n\nThis patcher converts `exit()` or `die()` statements to exceptions on the fly.\n\nIf you have a controller like below:\n\n~~~php\n    public function index()\n    {\n        $this-\u003eoutput\n            -\u003eset_status_header(200)\n            -\u003eset_content_type('application/json', 'utf-8')\n            -\u003eset_output(json_encode(['foo' =\u003e 'bar']))\n            -\u003e_display();\n        exit();\n    }\n~~~\n\nA test case could be like this:\n\n~~~php\n    public function test_index()\n    {\n        try {\n            $this-\u003erequest('GET', 'welcome/index');\n        } catch (ExitException $e) {\n            $output = ob_get_clean();\n        }\n        \n        $this-\u003eassertContains('{\"foo\":\"bar\"}', $output);\n    }\n~~~\n\n### Patch Functions\n\nThis patcher allows replacement of global functions that can't be mocked by PHPUnit.\n\nBut it has a few limitations. Some functions can't be replaced and it might cause errors.\n\nSo by default we can replace only a dozen pre-defined functions in [FunctionPatcher](https://github.com/kenjis/monkey-patch/blob/a11e1f227234dadeae2460d29b9c8ca6e91c88de/src/Patcher/FunctionPatcher.php#L31-L49).\n\n~~~php\n    public function test_index()\n    {\n        MonkeyPatch::patchFunction('mt_rand', 100, 'Welcome::index');\n        \n        $output = $this-\u003erequest('GET', 'welcome/index');\n        \n        $this-\u003eassertContains('100', $output);\n    }\n~~~\n\n`MonkeyPatch::patchFunction()` replaces PHP native function `mt_rand()` in `Welcome::index` method, and it will return `100` in the test method.\n\n**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.\n\n#### Change Return Value\n\nYou could change return value of patched function using PHP closure:\n\n~~~php\n        MonkeyPatch::patchFunction(\n            'function_exists',\n            function ($function) {\n                if ($function === 'random_bytes') {\n                    return true;\n                } elseif ($function === 'openssl_random_pseudo_bytes') {\n                    return false;\n                } elseif ($function === 'mcrypt_create_iv') {\n                    return false;\n                } else {\n                    return __GO_TO_ORIG__;\n                }\n            },\n            Welcome::class\n        );\n~~~\n\n#### Patch Other Functions\n\nIf you want to patch other functions, you can add them to [functions_to_patch](https://github.com/kenjis/monkey-patch/blob/a11e1f227234dadeae2460d29b9c8ca6e91c88de/src/bootstrap.php#L56-L59) in `MonkeyPatchManager::init()`.\n\nBut there are a few known limitations:\n\n- Patched functions which have parameters called by reference don't work.\n- You may see visibility errors if you pass non-public callbacks to patched functions. For example, you pass `[$this, 'method']` to `array_map()` and the `method()` method in the class is not public.\n\n### Patch Methods in User-defined Classes\n\nThis patcher allows replacement of methods in user-defined classes.\n\n~~~php\n    public function test_index()\n    {\n        MonkeyPatch::patchMethod(\n            Category_model::class,\n            ['get_category_list' =\u003e [(object) ['name' =\u003e 'Nothing']]]\n        );\n        \n        $output = $this-\u003erequest('GET', 'welcome/index');\n        \n        $this-\u003eassertContains('Nothing', $output);\n    }\n~~~\n\n`MonkeyPatch::patchMethod()` replaces `get_category_list()` method in `Category_model`, and it will return `[(object) ['name' =\u003e 'Nothing']]` in the test method.\n\n### Patch Constants\n\nThis patcher allows replacement of constant value.\n\n~~~php\n    public function test_index()\n    {\n        MonkeyPatch::patchConstant(\n            'ENVIRONMENT', \n            'development', \n            Welcome::class . '::index'\n        );\n\n        $output = $this-\u003erequest('GET', 'welcome/index');\n\n        $this-\u003eassertContains('development', $output);\n    }\n~~~\n\n`MonkeyPatch::patchConstant()` replaces the return value of the constant `ENVIRONMENT` in `Welcome::index` method.\n\nThere are a few known limitations:\n\n- Cannot patch constants that are used as default values in function arguments.\n- Cannot patch constants that are used as default values in constant declarations.\n- Cannot patch constants that are used as default values in property declarations.\n- Cannot patch constants that are used as default values in static variable declarations.\n\n## Class Reference\n\nSee [ci-phpunit-test docs](https://github.com/kenjis/ci-phpunit-test/blob/3.x/docs/FunctionAndClassReference.md#class-monkeypatch).\n\n## License\n\nThis package is licensed using the MIT License.\n\nPlease have a look at [`LICENSE`](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjis%2Fmonkey-patch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenjis%2Fmonkey-patch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenjis%2Fmonkey-patch/lists"}