From cbd539815df07c40595c8c8a299a735286c9b858 Mon Sep 17 00:00:00 2001 From: Ignas Rudaitis Date: Wed, 28 Feb 2018 12:50:13 +0200 Subject: [PATCH 1/2] Begin #81 --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4bf78d --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# Patchwork 2.1 + + composer require antecedent/patchwork + +This library allows any function/method call to be intercepted. It does not depend on any core extensions. + +Here, the internally preferred jargon for this behavior is **function redefinition**, since this conceptualization is already familiar from Runkit and from related techniques in other languages. The two viewpoints are mostly equivalent from the perspective of a developer using Patchwork. **Monkey-patching** is yet another synonym. + +## Example of testing-related usage + +```php +use function Patchwork\{redefine, restoreAll, always}; + +final class ImportServiceTest extends PHPUnit\Framework\TestCase +{ + private $importService; // Assume a proper setUp() + private $calls = []; // Assume a logCall() method to populate this + + public function testNoImportOccursIfDataRecent() + { + redefine('file_get_contents', [$this, 'logCall']); + redefine('filemtime', always(strtotime('-2 days'))); + $this->importService->import(); + $this->assertEmpty($this->calls); + } + + public function tearDown() + { + restoreAll(); + $this->calls = []; + } +} +``` From e3941f6f88103b85c25e3556be2a53851d7a4c1e Mon Sep 17 00:00:00 2001 From: Ignas Rudaitis Date: Mon, 5 Mar 2018 18:41:41 +0200 Subject: [PATCH 2/2] Update README.md --- README.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e4bf78d..0f14637 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,41 @@ composer require antecedent/patchwork -This library allows any function/method call to be intercepted. It does not depend on any core extensions. - -Here, the internally preferred jargon for this behavior is **function redefinition**, since this conceptualization is already familiar from Runkit and from related techniques in other languages. The two viewpoints are mostly equivalent from the perspective of a developer using Patchwork. **Monkey-patching** is yet another synonym. +This library allows any function/method call to be intercepted, as if the function were redefined at runtime. It does not depend on any core extensions. ## Example of testing-related usage +Patchwork is used primarily to ease the testing of legacy code. + +Suppose that a hypothetical `ImportService` imports a remote resource using `file_get_contents()`, unless the local copy is sufficiently recent. The latter check is achieved using `filemtime()`. + +It follows that these functions are stubborn dependencies of `ImportService`, at least if they are called the usual way, that is, `file_get_contents($path)` and not `($this->fileReader)($path)`. + +What makes these dependencies stubborn is that they cannot be displaced using any conventional runtime strategies. Concretely, if `ImportService` calls `file_get_contents()`, then there is no non-invasive way of making it call something else instead for testing purposes. + +It is easy to avoid this issue and do without Patchwork, as in `function __construct($fileReader = 'file_get_contents')`. However, when presented with a legacy codebase where it is impractical to perform such refactoring, Patchwork will help: + ```php -use function Patchwork\{redefine, restoreAll, always}; +use function Patchwork\{redefine, restoreAll, always, getFunction}; final class ImportServiceTest extends PHPUnit\Framework\TestCase { - private $importService; // Assume a proper setUp() - private $calls = []; // Assume a logCall() method to populate this + private $importService = new ImportServiceTest; // FIXME + private $calls = []; public function testNoImportOccursIfDataRecent() { redefine('file_get_contents', [$this, 'logCall']); redefine('filemtime', always(strtotime('-2 days'))); + $this->calls = []; $this->importService->import(); $this->assertEmpty($this->calls); + restoreAll(); } - public function tearDown() + public function logCall() { - restoreAll(); - $this->calls = []; + $this->calls[] = Patchwork\getFunction(); } } ```