{"id":13622733,"url":"https://github.com/php-mock/php-mock","last_synced_at":"2025-04-13T03:59:23.109Z","repository":{"id":23793709,"uuid":"27169454","full_name":"php-mock/php-mock","owner":"php-mock","description":"Mock built-in PHP functions (e.g. time(), exec() or rand())","archived":false,"fork":false,"pushed_at":"2025-02-28T18:12:33.000Z","size":726,"stargazers_count":362,"open_issues_count":3,"forks_count":20,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-13T03:59:13.367Z","etag":null,"topics":["builtin-functions","mock","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/php-mock.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["michalbundyra"]}},"created_at":"2014-11-26T09:31:58.000Z","updated_at":"2025-03-06T15:15:33.000Z","dependencies_parsed_at":"2024-02-10T22:24:41.317Z","dependency_job_id":"247883d8-b1a4-4066-9e1f-116a228b1166","html_url":"https://github.com/php-mock/php-mock","commit_stats":{"total_commits":175,"total_committers":12,"mean_commits":"14.583333333333334","dds":0.3142857142857143,"last_synced_commit":"fff1a621ebe54100fa3bd852e7be57773a0c0127"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-mock%2Fphp-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-mock%2Fphp-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-mock%2Fphp-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-mock%2Fphp-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/php-mock","download_url":"https://codeload.github.com/php-mock/php-mock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248661706,"owners_count":21141450,"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":["builtin-functions","mock","php"],"created_at":"2024-08-01T21:01:23.472Z","updated_at":"2025-04-13T03:59:23.082Z","avatar_url":"https://github.com/php-mock.png","language":"PHP","readme":"# PHP-Mock: mocking built-in PHP functions\n\nPHP-Mock is a testing library which mocks non deterministic built-in PHP functions like\n`time()` or `rand()`. This is achieved by [PHP's namespace fallback policy](http://php.net/manual/en/language.namespaces.fallback.php):\n\n\u003e PHP will fall back to global functions […]\n\u003e if a namespaced function […] does not exist.\n\nPHP-Mock uses that feature by providing the namespaced function. I.e. you have\nto be in a **non global namespace** context and call the function\n**unqualified**:\n\n```php\nnamespace foo;\n\n$time = time(); // This call can be mocked, a call to \\time() can't.\n```\n\n## Requirements and restrictions\n\n* Only *unqualified* function calls in a namespace context can be mocked.\n  E.g. a call for `time()` in the namespace `foo` is mockable,\n  a call for `\\time()` is not.\n\n* The mock has to be defined before the first call to the unqualified function\n  in the tested class. This is documented in [Bug #68541](https://bugs.php.net/bug.php?id=68541).\n  In most cases, you can ignore this restriction but if you happen to run into\n  this issue you can call [`Mock::define()`](http://php-mock.github.io/php-mock/api/class-phpmock.Mock.html#_define)\n  before that first call. This would define a side effectless namespaced\n  function which can be enabled later. Another effective\n  approach is running your test in an isolated process.\n\n## Alternatives\n\nIf you can't rely on or just don't want to use the namespace fallback policy,\nthere are alternative techniques to mock built-in PHP functions:\n\n* [**PHPBuiltinMock**](https://github.com/jadell/PHPBuiltinMock) relies on\n  the [APD](http://php.net/manual/en/book.apd.php) extension.\n\n* [**MockFunction**](https://github.com/tcz/phpunit-mockfunction) is a PHPUnit\n  extension. It uses the [runkit](http://php.net/manual/en/book.runkit.php) extension.\n\n* [**UOPZ**](https://github.com/krakjoe/uopz) is a Zend extension which\n  allows, among others, renaming and deletion of functions.\n\n* [**vfsStream**](https://github.com/mikey179/vfsStream) is a stream wrapper for\n  a virtual file system. This will help you write tests which covers PHP\n  stream functions (e.g. `fread()` or `readdir()`).\n\n# Installation\n\nUse [Composer](https://getcomposer.org/):\n\n```sh\ncomposer require --dev php-mock/php-mock\n```\n\n\n# Usage\n\nYou don't need to learn yet another API. PHP-Mock has integrations\nfor these testing frameworks:\n\n- [php-mock/php-mock-phpunit](https://github.com/php-mock/php-mock-phpunit) - PHPUnit integration\n\n- [php-mock/php-mock-mockery](https://github.com/php-mock/php-mock-mockery) - Mockery integration\n\n- [php-mock/php-mock-prophecy](https://github.com/php-mock/php-mock-prophecy) - Prophecy (phpspec) integration\n\n**Note:** If you plan to use one of the above mentioned testing frameworks you can skip\nreading any further and just go to the particular integration project.\n\n## PHP-Mock API\n\nYou find the API in the namespace\n[`phpmock`](http://php-mock.github.io/php-mock/api/namespace-phpmock.html).\n\nCreate a [`Mock`](http://php-mock.github.io/php-mock/api/class-phpmock.Mock.html)\nobject. You can do this with the fluent API of [`MockBuilder`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html):\n\n* [`MockBuilder::setNamespace()`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html#_setNamespace)\n  sets the target namespace of the mocked function.\n\n* [`MockBuilder::setName()`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html#_setName)\n  sets the name of the mocked function (e.g. `time()`).\n\n* [`MockBuilder::setFunction()`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html#_setFunction)\n  sets the concrete mock implementation.\n\n* [`MockBuilder::setFunctionProvider()`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html#_setFunctionProvider)\n  sets, alternativly to `MockBuilder::setFunction()`, the mock implementation as a\n  [`FunctionProvider`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.FunctionProvider.html):\n\n   * [`FixedValueFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.FixedValueFunction.html)\n     is a simple implementation which returns always the same value.\n\n   * [`FixedMicrotimeFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.FixedMicrotimeFunction.html)\n     is a simple implementation which returns always the same microtime. This\n     class is different to `FixedValueFunction` as it contains a converter for\n     `microtime()`'s float and string format.\n\n   * [`FixedDateFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.FixedDateFunction.html)\n     is a simple implementation which returns always a formated date for the fixed timestamp.\n\n   * [`SleepFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.SleepFunction.html)\n     is a `sleep()` implementation, which doesn't halt but increases an\n     [`Incrementable`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.Incrementable.html)\n     e.g. a `time()` mock.\n\n   * [`UsleepFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.UsleepFunction.html)\n     is an `usleep()` implementation, which doesn't halt but increases an\n     `Incrementable` e.g. a `microtime()` mock.\n\n* [`MockBuilder::build()`](http://php-mock.github.io/php-mock/api/class-phpmock.MockBuilder.html#_build)\n  builds a `Mock` object.\n\nAfter you have build your `Mock` object you have to call [`enable()`](http://php-mock.github.io/php-mock/api/class-phpmock.Mock.html#_enable)\nto enable the mock in the given namespace. When you are finished with that mock you\nshould disable it by calling [`disable()`](http://php-mock.github.io/php-mock/api/class-phpmock.Mock.html#_disable)\non the mock instance. \n\nThis example illustrates mocking of the unqualified function `time()` in the \nnamespace `foo`:\n\n```php\nnamespace foo;\n\nuse phpmock\\MockBuilder;\n\n$builder = new MockBuilder();\n$builder-\u003esetNamespace(__NAMESPACE__)\n        -\u003esetName(\"time\")\n        -\u003esetFunction(\n            function () {\n                return 1417011228;\n            }\n        );\n                    \n$mock = $builder-\u003ebuild();\n\n// The mock is not enabled yet.\nassert (time() != 1417011228);\n\n$mock-\u003eenable();\nassert (time() == 1417011228);\n\n// The mock is disabled and PHP's built-in time() is called.\n$mock-\u003edisable();\nassert (time() != 1417011228);\n```\n\nInstead of setting the mock function with `MockBuilder::setFunction()` you could also\nuse the existing [`FixedValueFunction`](http://php-mock.github.io/php-mock/api/class-phpmock.functions.FixedValueFunction.html):\n\n```php\nnamespace foo;\n\nuse phpmock\\MockBuilder;\nuse phpmock\\functions\\FixedValueFunction;\n\n$builder = new MockBuilder();\n$builder-\u003esetNamespace(__NAMESPACE__)\n        -\u003esetName(\"time\")\n        -\u003esetFunctionProvider(new FixedValueFunction(1417011228));\n\n$mock = $builder-\u003ebuild();\n```\n\nIt's important to note that `setNamespace()` should target the namespace where the function is called, not the namespace where it's being mocked. For example:\n\n```\n\u003c?php\n\nnamespace App\\Code;\n\nclass Subject\n{\n  public function foo()\n  {\n    time();\n  }\n}\n```\n\nIn a test mocking this call:\n\n```\n\u003c?php\n\nnamespace Tests\\Unit;\n\nclass SubjectTest\n{\n  public function myTest()\n  {\n    $builder = new MockBuilder();\n    $builder-\u003esetNamespace('\\\\App\\\\Code'); // ... etc\n  }\n}\n```\n\n### Reset global state\n\nAn enabled mock changes global state. This will break subsequent tests if\nthey run code which would call the mock unintentionally. Therefore\nyou should always disable a mock after the test case. You will have to disable\nthe created mock. You could do this for all mocks by calling the\nstatic method\n[`Mock::disableAll()`](http://php-mock.github.io/php-mock/api/class-phpmock.Mock.html#_disableAll).\n\n### Mock environments\n\nComplex mock environments of several mocked functions can be grouped in a [`MockEnvironment`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.MockEnvironment.html):\n\n* [`MockEnvironment::enable()`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.MockEnvironment.html#_enable)\n  enables all mocked functions of this environment.\n\n* [`MockEnvironment::disable()`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.MockEnvironment.html#_disable)\n  disables all mocked functions of this environment.\n\n* [`MockEnvironment::define()`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.MockEnvironment.html#_define)\n  defines all mocked functions of this environment.\n\n#### SleepEnvironmentBuilder\n\nThe [`SleepEnvironmentBuilder`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.SleepEnvironmentBuilder.html)\nbuilds a mock environment where `sleep()` and `usleep()` return immediatly.\nFurthermore they increase the amount of time in the mocked `date()`, `time()` and\n`microtime()`:\n\n```php\nnamespace foo;\n\nuse phpmock\\environment\\SleepEnvironmentBuilder;\n\n$builder = new SleepEnvironmentBuilder();\n$builder-\u003eaddNamespace(__NAMESPACE__)\n        -\u003esetTimestamp(1417011228);\n\n$environment = $builder-\u003ebuild();\n$environment-\u003eenable();\n\n// This won't delay the test for 10 seconds, but increase time().        \nsleep(10);\n\nassert(1417011228 + 10 == time());\n```\n\nIf the mocked functions should be in different namespaces you can\nadd more namespaces with [`SleepEnvironmentBuilder::addNamespace()`](http://php-mock.github.io/php-mock/api/class-phpmock.environment.SleepEnvironmentBuilder.html#_addNamespace)\n\n### Spies\n\nA [`Spy`](http://php-mock.github.io/php-mock/api/class-phpmock.spy.Spy.html)\ngives you access to the function invocations.\n[`Spy::getInvocations()`](http://php-mock.github.io/php-mock/api/class-phpmock.spy.Spy.html#_getInvocations)\ngives you access to the arguments and return value.\n\nAs a `Spy` is a specialization of `Mock` it behaves identically. However you\ncould ommit the third constructor parameter `callable $function` which\nwould then create a spy using the existing function.\nE.g. a `new Spy(__NAMESPACE__ , \"rand\")` would create a spy which basically\nproxies PHP's built-in `rand()`:\n\n```php\nnamespace foo;\n\nuse phpmock\\spy\\Spy;\n\nfunction bar($min, $max) {\n    return rand($min, $max) + 3;\n}\n\n$spy = new Spy(__NAMESPACE__, \"rand\");\n$spy-\u003eenable();\n\n$result = bar(1, 2);\n\nassert ([1, 2]  == $spy-\u003egetInvocations()[0]-\u003egetArguments());\nassert ($result == $spy-\u003egetInvocations()[0]-\u003egetReturn() + 3);\n```\n\n\n# License and authors\n\nThis project is free and under the WTFPL.\nResponsable for this project is Markus Malkusch markus@malkusch.de.\nThis library was inspired by Fabian Schmengler's article\n[*PHP: “Mocking” built-in functions like time() in Unit Tests*](http://www.schmengler-se.de/en/2011/03/php-mocking-built-in-functions-like-time-in-unit-tests/).\n\n## Donations\n\nIf you like PHP-Mock and feel generous donate a few Bitcoins here:\n[1335STSwu9hST4vcMRppEPgENMHD2r1REK](bitcoin:1335STSwu9hST4vcMRppEPgENMHD2r1REK)\n","funding_links":["https://github.com/sponsors/michalbundyra"],"categories":["Table of Contents","PHP","目录"],"sub_categories":["Testing","测试 Testing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-mock%2Fphp-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphp-mock%2Fphp-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-mock%2Fphp-mock/lists"}