{"tag":"mock","articles":{"blog\/technology\/perfect-code-coverage":{"key":"blog\/technology\/perfect-code-coverage","type":"article","published":true,"meta":{"createdAt":"2017-12-25T00:26:11+01:00","publishedAt":"2017-12-25T13:30:00+01:00","group":"mocks","category":"blog","subcategory":"technology","slug":"perfect-code-coverage"},"content":{"en":{"slug":"perfect-code-coverage","title":"Perfect code coverage","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/coverage_small.png\u0022 alt=\u0022100% coverage - feels good!\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022203.90824129142\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADkklEQVRIibWWXYscRRSGn1Pd1R\/T053t3TXZ3QghaiDoteLdguAvyn\/ywh8RxIg3XngpIoKyH3Eyk5lZp6e7q7qry4tZJ5nNigbMCwUF\/RTn7ToflFhr\/dXVFd57vPeICBsJ4NFaYxxYB3Eo5GnEu1IQBIhzzjvn3lmQt5FSivDvzW3avbF\/V9\/3vHz5EgDnHCcnJ29tSkzX+qpZEUX6jY8rWzFrNwEynbEX3mHyx4SjoyO0DmlbA3iM6pi3c+q6xtU9R\/k9qtUaFSgODg7QOkIp4aK5BGA6nXIcHoMTet\/x8MMHtK1hlGSEjan44acfuXtyQhorYv3qtn6e\/8I3F98C8EHxkC8ffEHt\/+RiYcnyEetVhTWWSyZ89\/x7AB7tfcTx+D1svSbNMlq1Yras8AJf\/fY1AHuUPPn8CVpHWGv5ffYrnW855AjlgdEoAUAHu+lRIgQSXq8AgCjWBOFmr6OIKI4JJHjFoa65iCBQIILWGhWoLcNz4fLyOU+fPkVrTR7toSONUrKpIUHAQ+8ges1THCQcJgcA5NEYPDtrcI7BOeIg3nLjKN9hvBuwtkeFast8+slnWGs5PT0F4Pz8jPRQQyKEfvA0xpIAHg+vFXHjGibN5LqGRiDQdR2iAhBIRgnW2h2uiPMtF2iNBIogVDjvtszZ\/Jz8XsGzZ894\/PgxnRiKaLTJCnjqtSFUslM\/cP2XN+Scw\/sBANMaOtvh\/Zugcw4\/DPhhoLP9DtO3PcYY8jxHKUV+Z4xpWwY\/EIoIRZ4S69vb+2aoJE0I9aYjRYQkTRAr\/8CFiFIkaYTzm1nnPdzfP6EsS8qyxFrLo+OPmV29wJkBaZq1v5jOyfI7uMGjBPbHMSIwDMMmjZvwBNfzqmka0jQFoG0adBSD3OC8p2kNaZrQ9z11XdM7R9PU3D96n+l0SlmWLJdL0jRFRMiyDBmG4ZbE\/L8ahoGqqiiKgqqq0FpT1zXj8RhrLVmWbVlljeHi8pJqvX5nhlarFVmWsVgs0FrT9z3WWrTWtG0LwNnZGefn50jXNn42eYESwXtPURZM51NGaYKIwuNJsozJbEYURwgQxQl39+79JzN1XWOtRSlFURR0XUfTNCRJgjFma9QYQ1EUSNu2vq7rTXCdIsAweMJQcKYmiDMC8XTWMiiNVkLfW1CaIFAMptqMgddeC3EcE8cxAMvlkrIst122WCwoyxIRYT6fs7+\/vz3nvecvzIfJZKZPRaUAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/coverage_small.png\u0022 alt=\u0022100% coverage - feels good!\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022203.90824129142\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHaving 100% of LOC covered by unit tests certainly feels like a great achievement. But beware \u2013 that doesn\u2019t necessarily mean your code is \u003Cem\u003Eperfectly\u003C\/em\u003E covered. Lines of code coverage is a really nice indicator of your app\u2019s stability, but is can also hide some  risks.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/coverage_big.png\u0022 alt=\u0022100% coverage - feels good!\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022407.81648258284\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADkklEQVRIibWWXYscRRSGn1Pd1R\/T053t3TXZ3QghaiDoteLdguAvyn\/ywh8RxIg3XngpIoKyH3Eyk5lZp6e7q7qry4tZJ5nNigbMCwUF\/RTn7ToflFhr\/dXVFd57vPeICBsJ4NFaYxxYB3Eo5GnEu1IQBIhzzjvn3lmQt5FSivDvzW3avbF\/V9\/3vHz5EgDnHCcnJ29tSkzX+qpZEUX6jY8rWzFrNwEynbEX3mHyx4SjoyO0DmlbA3iM6pi3c+q6xtU9R\/k9qtUaFSgODg7QOkIp4aK5BGA6nXIcHoMTet\/x8MMHtK1hlGSEjan44acfuXtyQhorYv3qtn6e\/8I3F98C8EHxkC8ffEHt\/+RiYcnyEetVhTWWSyZ89\/x7AB7tfcTx+D1svSbNMlq1Yras8AJf\/fY1AHuUPPn8CVpHWGv5ffYrnW855AjlgdEoAUAHu+lRIgQSXq8AgCjWBOFmr6OIKI4JJHjFoa65iCBQIILWGhWoLcNz4fLyOU+fPkVrTR7toSONUrKpIUHAQ+8ges1THCQcJgcA5NEYPDtrcI7BOeIg3nLjKN9hvBuwtkeFast8+slnWGs5PT0F4Pz8jPRQQyKEfvA0xpIAHg+vFXHjGibN5LqGRiDQdR2iAhBIRgnW2h2uiPMtF2iNBIogVDjvtszZ\/Jz8XsGzZ894\/PgxnRiKaLTJCnjqtSFUslM\/cP2XN+Scw\/sBANMaOtvh\/Zugcw4\/DPhhoLP9DtO3PcYY8jxHKUV+Z4xpWwY\/EIoIRZ4S69vb+2aoJE0I9aYjRYQkTRAr\/8CFiFIkaYTzm1nnPdzfP6EsS8qyxFrLo+OPmV29wJkBaZq1v5jOyfI7uMGjBPbHMSIwDMMmjZvwBNfzqmka0jQFoG0adBSD3OC8p2kNaZrQ9z11XdM7R9PU3D96n+l0SlmWLJdL0jRFRMiyDBmG4ZbE\/L8ahoGqqiiKgqqq0FpT1zXj8RhrLVmWbVlljeHi8pJqvX5nhlarFVmWsVgs0FrT9z3WWrTWtG0LwNnZGefn50jXNn42eYESwXtPURZM51NGaYKIwuNJsozJbEYURwgQxQl39+79JzN1XWOtRSlFURR0XUfTNCRJgjFma9QYQ1EUSNu2vq7rTXCdIsAweMJQcKYmiDMC8XTWMiiNVkLfW1CaIFAMptqMgddeC3EcE8cxAMvlkrIst122WCwoyxIRYT6fs7+\/vz3nvecvzIfJZKZPRaUAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/coverage_big.png\u0022 alt=\u0022100% coverage - feels good!\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022407.81648258284\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHaving 100% of LOC covered by unit tests certainly feels like a great achievement. But beware \u2013 that doesn\u2019t necessarily mean your code is \u003Cem\u003Eperfectly\u003C\/em\u003E covered. Lines of code coverage is a really nice indicator of your app\u2019s stability, but is can also hide some  risks.\u003C\/p\u003E\n\u003Ch3\u003ECyclomatic complexity\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s say you have simple method to test:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EcalculateStuff\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E: \u003Cspan class=\u0022hljs-title\u0022\u003Eint\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;debug) {\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ do some stuff\u003C\/span\u003E\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $result;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EHow many test cases should you write for it? Obviously, two: one to check for a valid output if \u003Ccode\u003Edebug\u003C\/code\u003E is true, and one when it\u2019s false. If you only write one of them, LOC coverage will make it clearly visible that something is missing. But what if your code looks like this?\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EcalculateStuff\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E: \u003Cspan class=\u0022hljs-title\u0022\u003Eint\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;debug ? \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;calculateResult() : \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EYou still have exactly the same two \u003Cem\u003Elogic paths\u003C\/em\u003E, but only one line of code. Testing any of those paths will result in the entire method being \u201ccovered\u201d.\u003C\/p\u003E\n\u003Cp\u003EAnd what about this code?\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EonException\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E(ExceptionEvent $event)\u003C\/span\u003E:\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;debug) {\n        $event-\u0026gt;setResponse(\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;renderErrorPage());\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf you first test the case when \u003Ccode\u003E$debug === false\u003C\/code\u003E, then grab some lunch, and then come back not remembering the details, but seeing a 100% coverage \u2013 will you remember to also test the other case?\u003C\/p\u003E\n\u003Cp\u003ESumming up: having the tests execute every single \u003Cstrong\u003Eline\u003C\/strong\u003E of your code still does not guarantee that all the \u003Cstrong\u003Elogical paths\u003C\/strong\u003E of your class are being executed.\u003C\/p\u003E\n\u003Ch3\u003EMissing assertions\u003C\/h3\u003E\n\u003Cp\u003EAlso: having all the logical paths \u003Cstrong\u003Eexecuted\u003C\/strong\u003E doesn\u2019t necessarily mean you got them \u003Cstrong\u003Etested\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EFoo\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Erun\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E($input)\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ lots of complex logic\u003C\/span\u003E\n\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ write the result to a file\u003C\/span\u003E\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $output;\n    }\n\n    \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ lots of private methods\u003C\/span\u003E\n}\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EFooTest\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ETestCase\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EtestRun\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $foo = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Foo;\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;assertEquals(\u003Cspan class=\u0022hljs-number\u0022\u003E8\u003C\/span\u003E, $foo-\u0026gt;run(\u003Cspan class=\u0022hljs-number\u0022\u003E123\u003C\/span\u003E));\n        \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ other, similar test cases\u003C\/span\u003E\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt\u2019s very possible this test will cover every single line of those \u003Ccode\u003Elots of complex logic\u003C\/code\u003E. But what about the side effects? We are writing something to a file after all (a log maybe?). We are testing that the output is correct for a given input, but we forgot to test that the side effects are also working as expected.\u003C\/p\u003E\n\u003Cp\u003EThe nicest would be, of course, to avoid any side effects and code more functional-programming-style, but that might not always be doable easily enough. So the second best thing would be this: don\u2019t trust your coverage, check if what was covered, was also tested.\u003C\/p\u003E\n\u003Ch3\u003ELeaky coverage\u003C\/h3\u003E\n\u003Cp\u003EIt\u2019s virtually impossible to mock \u003Cem\u003Eall\u003C\/em\u003E the dependencies away. Well, ok, it\u2019s \u003Cem\u003Epossible\u003C\/em\u003E, but sometimes it\u2019s more effort than it\u2019s \u003Cem\u003Eworth\u003C\/em\u003E. Most of the time when you\u2019re testing class \u003Ccode\u003EX\u003C\/code\u003E, some lines of classes \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E will also get executed. Usually, it\u2019s harmless. But sometimes it could blow up in your face \u2013 you could get the entire class \u003Ccode\u003EY\u003C\/code\u003E \u201ccovered\u201d without actually testing it. It\u2019s then very tempting to just leave it as it is (100% achieved, why would I even bother?) and very simple to just miss it.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why it\u2019s a great habit to tell the testing framework, what are you testing with this specific case. In \u003Ca href=\u0022https:\/\/phpunit.de\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PHPUnit\u003C\/a\u003E you can do it using the \u003Ccode\u003E@covers\u003C\/code\u003E annotation. If you specify that \u003Ccode\u003EXTest\u003C\/code\u003E \u003Ccode\u003E@covers X\u003C\/code\u003E, PHPUnit will still execute the code of \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E, but will not count that as a coverage of \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E.\u003C\/p\u003E\n\u003Ch3\u003EAchieving 100%\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s not kid ourselves \u2013 the test cases for more complex applications are never \u003Cem\u003Eperfect\u003C\/em\u003E in the sense of covering every single scenario that your code might run into. It\u2019s just not worth the effort, \u201cgood enough\u201d is usually good enough.\u003C\/p\u003E\n\u003Cp\u003EStill, having high coverage is a good indicator. The higher it is, and the more \u003Cem\u003Emeaningful\u003C\/em\u003E it is (in terms of what I wrote above) \u2013 the safer you can feel when refactoring your code, or modifying it in any other way.\u003C\/p\u003E\n\u003Cp\u003EBut getting to 100% is not easy.\u003C\/p\u003E\n\u003Ch4\u003ETestable code\u003C\/h4\u003E\n\u003Cp\u003EFollow clean code rules and use design patterns. If you repeat yourself (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Don%27t_repeat_yourself\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E DRY\u003C\/a\u003E), you\u2019ll have to repeat the tests as well. If your class has multiple responsibilities (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Single_responsibility_principle\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E SRP\u003C\/a\u003E), it becomes considerably more difficult to test it. Testing (A+B) together can sometimes be way way harder than testing A + testing B.\u003C\/p\u003E\n\u003Cp\u003EUse \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Inversion_of_control\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E inversion of control\u003C\/a\u003E, like \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E DI\u003C\/a\u003E. If your class creates its dependencies or fetches them as a singleton, it\u2019s almost impossible to reliably mock those dependencies away. If you just pass them in the constructor though \u2013 it\u2019s an easy peasy to just pass a mock instead of an actual object.\u003C\/p\u003E\n\u003Cp\u003EThe simpler your code, the easier it is to test it. When writing tests for \u003Ca href=\u0022\/projects\/micrus-v4\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus\u003C\/a\u003E v4.0, I was surprised how much has my coverage grew not by adding new tests but by removing some not-so-useful, outdated or too complex code.\u003C\/p\u003E\n\u003Ch4\u003EAspectMock\u003C\/h4\u003E\n\u003Cp\u003EThere is a really fancy and clever library for PHP, \u003Ca href=\u0022https:\/\/github.com\/Codeception\/AspectMock\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E AspectMock\u003C\/a\u003E, that uses the power of aspect oriented programming to \u003Cem\u003Emake everything testable\u003C\/em\u003E. Static methods, final classes, global system functions, dependencies created inside of the tested class \u2013 everything. It basically modifies the source code in run-time, letting you do \u003Cem\u003Eanything\u003C\/em\u003E with it.\u003C\/p\u003E\n\u003Cp\u003EAwesome as it may be, I\u2019ve decided to move away from it. Micrus v4.0 doesn\u2019t use it all, even though in v3.0 it was a basis for every single mock. Why?\u003C\/p\u003E\n\u003Cp\u003EIt\u2019s quite an overhead, both in terms of speed and the time spent to configure it (best case scenario is very simple, but as soon as anything is misconfigured, debugging becomes a nightmare).\u003C\/p\u003E\n\u003Cp\u003EBut most importantly: it \u003Cem\u003Elets you get away with ugly code\u003C\/em\u003E. Why would you care about passing the dependencies in the constructor, if AspectMock lets you mock all the anti-patterns you can think of? Why would you care about making your code testable (= simple), if \u003Cem\u003Eeverything is testable\u003C\/em\u003E?\u003C\/p\u003E\n\u003Cp\u003EIf you depend on a legacy code, AspectMock might be your only chance to test some parts of it at all. However, if you\u2019re writing something modern \u2013 I\u2019d recommend avoiding this kind of magic.\u003C\/p\u003E\n\u003Ch4\u003EAlternatives\u003C\/h4\u003E\n\u003Cp\u003EHow to achieve 100% coverage without resolving to AspectMock or similar magic? I\u2019ve got some advice more specific than just SOLID or DI (although they are essential).\u003C\/p\u003E\n\u003Cp\u003EMost importantly: mocking the global functions. That\u2019s the feature for which I was considering staying with AspectMock after all. Then I found \u003Ca href=\u0022https:\/\/marcelog.github.io\/articles\/php_mock_global_functions_for_unit_tests_with_phpunit.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E this article\u003C\/a\u003E, showing how to achieve a similar result without that much overhead. It wasn\u2019t easy to use and re-use though, so I decided to write a solution which is. That\u2019s how \u003Ca href=\u0022\/projects\/avris-functionmock\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris FunctionMock\u003C\/a\u003E was born.\u003C\/p\u003E\n\u003Cp\u003EBasically it lets you write something like:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003EFunctionMock::create(\u003Cspan class=\u0022hljs-keyword\u0022\u003E__NAMESPACE__\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027time\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-number\u0022\u003E123456789\u003C\/span\u003E);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003Eand it will make all the calls to \u003Ccode\u003Etime()\u003C\/code\u003E inside \u003Ccode\u003E__NAMESPACE__\u003C\/code\u003E return \u003Ccode\u003E123456789\u003C\/code\u003E regardless of what the actual time is. You can also use a callback, disable a mock and validate how many times and with what arguments was the mock invoked.\u003C\/p\u003E\n\u003Cp\u003EWhen it comes to the issue of accessing private\/protected methods\/properties (which you shouldn\u2019t do, but sometimes have to), reflections come to the rescue:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$r = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E \\ReflectionProperty(Application::class, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027commands\u0027\u003C\/span\u003E);\n$r-\u0026gt;setAccessible(\u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E);\n$commands = array_keys($r-\u0026gt;getValue($consoleApp));\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;assertEquals([\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027help\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027list\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E], $commands);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003Eor\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$r = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E \\ReflectionMethod(FillEnvCommand::class, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027getDefaults\u0027\u003C\/span\u003E);\n$r-\u0026gt;setAccessible(\u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E);\n$defaults = iterator_to_array($r-\u0026gt;invoke($command));\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf you\u2019re being nice and keep your classes \u003Ccode\u003Efinal\u003C\/code\u003E (to enforce \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Composition_over_inheritance\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Composition over inheritance\u003C\/a\u003E), you should also be nice and make them implement an interface and depend on that interface (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_inversion_principle\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Dependency inversion principle\u003C\/a\u003E). You can\u2019t mock a final class \u2013 but you can mock that interface.\u003C\/p\u003E\n\u003Cp\u003EAnd when it comes to mocking static methods \u2013 if you need to mock them, you\u2019re doing something wrong. Static methods should be avoided, except for things like factories etc.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003EHaving high code coverage is nice, but remember it might give you a false feeling of security. Don\u2019t rely simply on that one number. And that\u2019s basically all I wanted to say \ud83d\ude01\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["aspectmock","code","coverage","mock","php","phpunit","programming","tests","unit tests"],"hasMore":true,"image":"https:\/\/avris.it\/image\/coverage_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/coverage_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/coverage_mini.png\u0022 alt=\u0022100% coverage - feels good!\u0022 width=\u0022240\u0022 height=\u0022101.95412064571\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHaving 100% of LOC covered by unit tests certainly feels like a great achievement. But beware \u2013 that doesn\u2019t necessarily mean your code is \u003Cem\u003Eperfectly\u003C\/em\u003E covered. Lines of code coverage is a really nice indicator of your app\u2019s stability, but is can also hide some  risks.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/coverage_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/coverage_mini.png\u0022 alt=\u0022100% coverage - feels good!\u0022 width=\u0022240\u0022 height=\u0022101.95412064571\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EHaving 100% of LOC covered by unit tests certainly feels like a great achievement. But beware \u2013 that doesn\u2019t necessarily mean your code is \u003Cem\u003Eperfectly\u003C\/em\u003E covered. Lines of code coverage is a really nice indicator of your app\u2019s stability, but is can also hide some  risks.\u003C\/p\u003E\n\u003Ch3\u003ECyclomatic complexity\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s say you have simple method to test:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003Epublic function calculateStuff(): int\n{\n    if ($this-\u0026gt;debug) {\n        \/\/ do some stuff\n        return $result;\n    }\n\n    return 0;\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EHow many test cases should you write for it? Obviously, two: one to check for a valid output if \u003Ccode\u003Edebug\u003C\/code\u003E is true, and one when it\u2019s false. If you only write one of them, LOC coverage will make it clearly visible that something is missing. But what if your code looks like this?\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003Epublic function calculateStuff(): int\n{\n    return $this-\u0026gt;debug ? $this-\u0026gt;calculateResult() : 0;\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EYou still have exactly the same two \u003Cem\u003Elogic paths\u003C\/em\u003E, but only one line of code. Testing any of those paths will result in the entire method being \u201ccovered\u201d.\u003C\/p\u003E\n\u003Cp\u003EAnd what about this code?\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003Epublic function onException(ExceptionEvent $event):\n{\n    if (!$this-\u0026gt;debug) {\n        $event-\u0026gt;setResponse($this-\u0026gt;renderErrorPage());\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf you first test the case when \u003Ccode\u003E$debug === false\u003C\/code\u003E, then grab some lunch, and then come back not remembering the details, but seeing a 100% coverage \u2013 will you remember to also test the other case?\u003C\/p\u003E\n\u003Cp\u003ESumming up: having the tests execute every single \u003Cstrong\u003Eline\u003C\/strong\u003E of your code still does not guarantee that all the \u003Cstrong\u003Elogical paths\u003C\/strong\u003E of your class are being executed.\u003C\/p\u003E\n\u003Ch3\u003EMissing assertions\u003C\/h3\u003E\n\u003Cp\u003EAlso: having all the logical paths \u003Cstrong\u003Eexecuted\u003C\/strong\u003E doesn\u2019t necessarily mean you got them \u003Cstrong\u003Etested\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003Eclass Foo\n{\n    public function run($input)\n    {\n        \/\/ lots of complex logic\n\n        \/\/ write the result to a file\n\n        return $output;\n    }\n\n    \/\/ lots of private methods\n}\n\nclass FooTest extends TestCase\n{\n    public function testRun()\n    {\n        $foo = new Foo;\n\n        $this-\u0026gt;assertEquals(8, $foo-\u0026gt;run(123));\n        \/\/ other, similar test cases\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt\u2019s very possible this test will cover every single line of those \u003Ccode\u003Elots of complex logic\u003C\/code\u003E. But what about the side effects? We are writing something to a file after all (a log maybe?). We are testing that the output is correct for a given input, but we forgot to test that the side effects are also working as expected.\u003C\/p\u003E\n\u003Cp\u003EThe nicest would be, of course, to avoid any side effects and code more functional-programming-style, but that might not always be doable easily enough. So the second best thing would be this: don\u2019t trust your coverage, check if what was covered, was also tested.\u003C\/p\u003E\n\u003Ch3\u003ELeaky coverage\u003C\/h3\u003E\n\u003Cp\u003EIt\u2019s virtually impossible to mock \u003Cem\u003Eall\u003C\/em\u003E the dependencies away. Well, ok, it\u2019s \u003Cem\u003Epossible\u003C\/em\u003E, but sometimes it\u2019s more effort than it\u2019s \u003Cem\u003Eworth\u003C\/em\u003E. Most of the time when you\u2019re testing class \u003Ccode\u003EX\u003C\/code\u003E, some lines of classes \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E will also get executed. Usually, it\u2019s harmless. But sometimes it could blow up in your face \u2013 you could get the entire class \u003Ccode\u003EY\u003C\/code\u003E \u201ccovered\u201d without actually testing it. It\u2019s then very tempting to just leave it as it is (100% achieved, why would I even bother?) and very simple to just miss it.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why it\u2019s a great habit to tell the testing framework, what are you testing with this specific case. In \u003Ca href=\u0022https:\/\/phpunit.de\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PHPUnit\u003C\/a\u003E you can do it using the \u003Ccode\u003E@covers\u003C\/code\u003E annotation. If you specify that \u003Ccode\u003EXTest\u003C\/code\u003E \u003Ccode\u003E@covers X\u003C\/code\u003E, PHPUnit will still execute the code of \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E, but will not count that as a coverage of \u003Ccode\u003EY\u003C\/code\u003E and \u003Ccode\u003EZ\u003C\/code\u003E.\u003C\/p\u003E\n\u003Ch3\u003EAchieving 100%\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s not kid ourselves \u2013 the test cases for more complex applications are never \u003Cem\u003Eperfect\u003C\/em\u003E in the sense of covering every single scenario that your code might run into. It\u2019s just not worth the effort, \u201cgood enough\u201d is usually good enough.\u003C\/p\u003E\n\u003Cp\u003EStill, having high coverage is a good indicator. The higher it is, and the more \u003Cem\u003Emeaningful\u003C\/em\u003E it is (in terms of what I wrote above) \u2013 the safer you can feel when refactoring your code, or modifying it in any other way.\u003C\/p\u003E\n\u003Cp\u003EBut getting to 100% is not easy.\u003C\/p\u003E\n\u003Ch4\u003ETestable code\u003C\/h4\u003E\n\u003Cp\u003EFollow clean code rules and use design patterns. If you repeat yourself (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Don%27t_repeat_yourself\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E DRY\u003C\/a\u003E), you\u2019ll have to repeat the tests as well. If your class has multiple responsibilities (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Single_responsibility_principle\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E SRP\u003C\/a\u003E), it becomes considerably more difficult to test it. Testing (A+B) together can sometimes be way way harder than testing A + testing B.\u003C\/p\u003E\n\u003Cp\u003EUse \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Inversion_of_control\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E inversion of control\u003C\/a\u003E, like \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E DI\u003C\/a\u003E. If your class creates its dependencies or fetches them as a singleton, it\u2019s almost impossible to reliably mock those dependencies away. If you just pass them in the constructor though \u2013 it\u2019s an easy peasy to just pass a mock instead of an actual object.\u003C\/p\u003E\n\u003Cp\u003EThe simpler your code, the easier it is to test it. When writing tests for \u003Ca href=\u0022\/projects\/micrus-v4.lite\u0022\u003E Micrus\u003C\/a\u003E v4.0, I was surprised how much has my coverage grew not by adding new tests but by removing some not-so-useful, outdated or too complex code.\u003C\/p\u003E\n\u003Ch4\u003EAspectMock\u003C\/h4\u003E\n\u003Cp\u003EThere is a really fancy and clever library for PHP, \u003Ca href=\u0022https:\/\/github.com\/Codeception\/AspectMock\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E AspectMock\u003C\/a\u003E, that uses the power of aspect oriented programming to \u003Cem\u003Emake everything testable\u003C\/em\u003E. Static methods, final classes, global system functions, dependencies created inside of the tested class \u2013 everything. It basically modifies the source code in run-time, letting you do \u003Cem\u003Eanything\u003C\/em\u003E with it.\u003C\/p\u003E\n\u003Cp\u003EAwesome as it may be, I\u2019ve decided to move away from it. Micrus v4.0 doesn\u2019t use it all, even though in v3.0 it was a basis for every single mock. Why?\u003C\/p\u003E\n\u003Cp\u003EIt\u2019s quite an overhead, both in terms of speed and the time spent to configure it (best case scenario is very simple, but as soon as anything is misconfigured, debugging becomes a nightmare).\u003C\/p\u003E\n\u003Cp\u003EBut most importantly: it \u003Cem\u003Elets you get away with ugly code\u003C\/em\u003E. Why would you care about passing the dependencies in the constructor, if AspectMock lets you mock all the anti-patterns you can think of? Why would you care about making your code testable (= simple), if \u003Cem\u003Eeverything is testable\u003C\/em\u003E?\u003C\/p\u003E\n\u003Cp\u003EIf you depend on a legacy code, AspectMock might be your only chance to test some parts of it at all. However, if you\u2019re writing something modern \u2013 I\u2019d recommend avoiding this kind of magic.\u003C\/p\u003E\n\u003Ch4\u003EAlternatives\u003C\/h4\u003E\n\u003Cp\u003EHow to achieve 100% coverage without resolving to AspectMock or similar magic? I\u2019ve got some advice more specific than just SOLID or DI (although they are essential).\u003C\/p\u003E\n\u003Cp\u003EMost importantly: mocking the global functions. That\u2019s the feature for which I was considering staying with AspectMock after all. Then I found \u003Ca href=\u0022https:\/\/marcelog.github.io\/articles\/php_mock_global_functions_for_unit_tests_with_phpunit.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E this article\u003C\/a\u003E, showing how to achieve a similar result without that much overhead. It wasn\u2019t easy to use and re-use though, so I decided to write a solution which is. That\u2019s how \u003Ca href=\u0022\/projects\/avris-functionmock.lite\u0022\u003E Avris FunctionMock\u003C\/a\u003E was born.\u003C\/p\u003E\n\u003Cp\u003EBasically it lets you write something like:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003EFunctionMock::create(__NAMESPACE__, \u0027time\u0027, 123456789);\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003Eand it will make all the calls to \u003Ccode\u003Etime()\u003C\/code\u003E inside \u003Ccode\u003E__NAMESPACE__\u003C\/code\u003E return \u003Ccode\u003E123456789\u003C\/code\u003E regardless of what the actual time is. You can also use a callback, disable a mock and validate how many times and with what arguments was the mock invoked.\u003C\/p\u003E\n\u003Cp\u003EWhen it comes to the issue of accessing private\/protected methods\/properties (which you shouldn\u2019t do, but sometimes have to), reflections come to the rescue:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$r = new \\ReflectionProperty(Application::class, \u0027commands\u0027);\n$r-\u0026gt;setAccessible(true);\n$commands = array_keys($r-\u0026gt;getValue($consoleApp));\n$this-\u0026gt;assertEquals([\u0027help\u0027, \u0027list\u0027, \u0027test\u0027], $commands);\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003Eor\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$r = new \\ReflectionMethod(FillEnvCommand::class, \u0027getDefaults\u0027);\n$r-\u0026gt;setAccessible(true);\n$defaults = iterator_to_array($r-\u0026gt;invoke($command));\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf you\u2019re being nice and keep your classes \u003Ccode\u003Efinal\u003C\/code\u003E (to enforce \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Composition_over_inheritance\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Composition over inheritance\u003C\/a\u003E), you should also be nice and make them implement an interface and depend on that interface (\u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_inversion_principle\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Dependency inversion principle\u003C\/a\u003E). You can\u2019t mock a final class \u2013 but you can mock that interface.\u003C\/p\u003E\n\u003Cp\u003EAnd when it comes to mocking static methods \u2013 if you need to mock them, you\u2019re doing something wrong. Static methods should be avoided, except for things like factories etc.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003EHaving high code coverage is nice, but remember it might give you a false feeling of security. Don\u2019t rely simply on that one number. And that\u2019s basically all I wanted to say \ud83d\ude01\u003C\/p\u003E","words":1332,"readTime":6,"lang":"en"}}},"projects\/avris-functionmock":{"key":"projects\/avris-functionmock","type":"article","published":true,"meta":{"createdAt":"2017-12-21T10:18:21+01:00","publishedAt":"2017-12-21T10:16:00+01:00","group":"mocks","links":[{"icon":"brands gitlab","colour":"primary","url":"https:\/\/gitlab.com\/Avris\/FunctionMock","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-functionmock"},"content":{"en":{"slug":"avris-functionmock","title":"Avris FunctionMock","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-function-mock_small.png\u0022 alt=\u0022Avris FunctionMock\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHpklEQVRIiX2X269dVRXGf+My59p7n7PPpZfTlkJLAVFStZFIJCFKIQEhBhM0atAE9UEfMD74J\/jumw9G47M+GV8QE41GIIFEwXgBRCLYAgVKS9tz2\/vsvdacw4e1W4waZ9ZcayVrXr75fXPM8S05duPJiFIRgqgVomLu1FIIAhXB1TBVkjvz+YxaK0RABAKICEJfRAQRAYKrJSIWtV57EhURUBHMHROhaYZ4hBARlFqQAAFKKQj9wKraAxWFWkmqdIsJEFm041p7EQBBVd6fXK6+C1ELokbE+\/0MIamhteBXOwhKUIkADUG0n4wQVB0QulIxBEUIUUx1wUa\/EKT\/trgWN8PdmM9bRCCiX6CIoou+poqbkVTxEIVaFgT3jBCBhKBquCkmgonipkhUaq3UWvoB3PvV14qqXZNKRYhaCYLVtTWuXLoMVAhBHKIWVAUCzJRkRvKrgARQgbpgS0BEFzIYimJmZEuMmgaiYzKd0rjTJCd7otZKKR1dKSD0+6VWAI4c2mC2vQPUnrQIVPMClGLaS5xNcdFERIuEgVT02iYV1Kyn1hIqioqh4iw1S6wPV7m8s4mGEiVoPKGeIQohQte1PUMCx48d450zryMSSICpIASQEImFZEoyxTVlumARMXY1VkC1Z0cNUyO7ky2hGCKJJidOHFxmd7LDrG05dHiD+XTCztY2JkJ2pUblrvvv5tWXXmYlNwTRRxag2ouiCiKQTMlueGhC0kIuhBpgoqgaKoqb42pkz7gIyZwkiaQN+\/at8rmvfYF962v87me\/5I2zb2DNMsn7aBqvLnPXvXfz4pPPsDYYAoWI6MGooAJmgmnPmrvg5AbpnFpjoS+AImqoOSKGm6OacLNFTZx+8JM88q0v8cpzf+Px7\/+UROHWI9cRtbK9u4Nn4yvf\/Q7P\/fwJrl9ZYV5aanRElF46XURX6vdQToopuAyWqG1Bau3PoQDEEHHUEskcVSOZM0iZkTtff+zzfPrh0+xc3uaJHz5O1iHrowE333Idu5sX2Zzsce+3v0xSoZ59kw8d2WBnOmGvm1NqR6ktaCW5YSa4K8mFlAyX0Qoy76BUAvo9giKSUDHEE1mdQUqMUuKRR+\/j0w+fBuAvT79AomG8PGZ51LB9acrxj3+U+x+6Cx80PPu9H7NxYBWNls2toOsSJXpAIRXVIGXHXUhJ8Sy4DMeQOyggoRCKoCAOmjB1kjk5JU6dOsFnv3jPtZSwdX6H\/YcOcvT4BsdP3sANt9\/E0oEVIoI3fvUUS8NMqcsMmo7cVJBKjZaumxO1RQ1UA3MjN44nwRmvQleIkB5M9NFlOK4JxZHFAfjoNx+8djIDPPCN+\/jPEhGce+p55hcucvDG\/cw2M+3uFVa0RawiFtTaUrsZQoeaYK6knPGmwXU8JhX6PIPioSSMLE4OI6uRUW4\/dYyjR\/f9F4B\/L7UUXv31H9h+5VUGS8pgdcTB266n21xi621BZY7QgmSiJERqH2HJsZyxZoiP18aUAiwYMgQPZyDGAGWA0VThzk\/c8n\/B7FzY5KVfPMP8vQsMG0ChnU6YvNfiMme02lDb0p89BioJWcil7lgeoM0QP7xvSNcFtUANRUNRjBRCwhiE0hTh1psO\/E8g060Jf3\/6Bc798WWytAwHtU8dFaKFOjNolDxUIikmsZApoaZYymhukNRAHuIf3miY7LXMZ4V5VymlUmpFQpCoWBFMhAPro2sgdnemnH3lHGf+\/BrnXvwnTbSMvBCp4FSyVkIDLGDe50pJQfLATTATNCUkDyAZ5Ay5AR\/gD62\/xe5eZWenZWu3stMF2zOYzGGvhXknlA5+9IOfMN2dcuXiFruXtsilkCgkKgOtDK1jKQUrg8p8VGEcpBAG1tsMKS3qgWXDatC2hjGmnRk6SGxeHtEyQE6fPBArg8TeXm+V3DIhTsUJSRScqpmNw9dx\/uJFutI7AVejaRrWxsvMJlOyCY3C+nJmnIPVNOfIeuHEiXWo27z+9hV2plNKblm77ihP\/ub3nHl7xsqgsrExZtYGz760iz93rqIpEFUsGd4kRA3PDZ4ylhpUjdP3fIr5Sy9zcH0N1IlQjmwc4sKFyxxcX8VDmE+mnPzgCRoRdi+8yygHZd8Yn13iUPc611vH2lLHradG3HPTMS68vcV4CC4dB++8j8lff4vc8dXHolleoaswWBrjqUHVEXOSJ0QMAa7fv8YwJdZGDRcvbTNKjtTKbDrjwHjEZHePaDuWkhN7Mw6vLjFSWM7KQAvtlQtkq6yOKredXKNZgteef43xUGi8Y3joEHllFS8YO5MpWGK+vY3ILqC9F4regKsol997FykVSkVqpe7tQS1kM6QEEoHVQqL3xqOUGSdn7M5qkxglwbUwyrCz13LHR1Z487JSL3WsDGF85S0+8MDH8Mtn\/8G8bVHP1FLxZgjv\/0MggKeEqiIRRA00egBaK9J11wx+bWe4GFfOv84gD3ARVpdX2L+yhkdlMtlifWXMn1523jk75PzmHmfe22OYg0bnfKZ7Ezlw821RS6Gbz6ntjLQ0RkIo8z00NX06qB2eBwC95wa0BoogcdVD915cIxAqJoKr4AJKJZuhGnRdi1DYGDurA+PStLe5jcOdx+FfEghCLeMqGgkAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-function-mock_small.png\u0022 alt=\u0022Avris FunctionMock\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFunctionMock is a simple and elegant way to mock away system\/global functions in your tests.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-function-mock_big.png\u0022 alt=\u0022Avris FunctionMock\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHpklEQVRIiX2X269dVRXGf+My59p7n7PPpZfTlkJLAVFStZFIJCFKIQEhBhM0atAE9UEfMD74J\/jumw9G47M+GV8QE41GIIFEwXgBRCLYAgVKS9tz2\/vsvdacw4e1W4waZ9ZcayVrXr75fXPM8S05duPJiFIRgqgVomLu1FIIAhXB1TBVkjvz+YxaK0RABAKICEJfRAQRAYKrJSIWtV57EhURUBHMHROhaYZ4hBARlFqQAAFKKQj9wKraAxWFWkmqdIsJEFm041p7EQBBVd6fXK6+C1ELokbE+\/0MIamhteBXOwhKUIkADUG0n4wQVB0QulIxBEUIUUx1wUa\/EKT\/trgWN8PdmM9bRCCiX6CIoou+poqbkVTxEIVaFgT3jBCBhKBquCkmgonipkhUaq3UWvoB3PvV14qqXZNKRYhaCYLVtTWuXLoMVAhBHKIWVAUCzJRkRvKrgARQgbpgS0BEFzIYimJmZEuMmgaiYzKd0rjTJCd7otZKKR1dKSD0+6VWAI4c2mC2vQPUnrQIVPMClGLaS5xNcdFERIuEgVT02iYV1Kyn1hIqioqh4iw1S6wPV7m8s4mGEiVoPKGeIQohQte1PUMCx48d450zryMSSICpIASQEImFZEoyxTVlumARMXY1VkC1Z0cNUyO7ky2hGCKJJidOHFxmd7LDrG05dHiD+XTCztY2JkJ2pUblrvvv5tWXXmYlNwTRRxag2ouiCiKQTMlueGhC0kIuhBpgoqgaKoqb42pkz7gIyZwkiaQN+\/at8rmvfYF962v87me\/5I2zb2DNMsn7aBqvLnPXvXfz4pPPsDYYAoWI6MGooAJmgmnPmrvg5AbpnFpjoS+AImqoOSKGm6OacLNFTZx+8JM88q0v8cpzf+Px7\/+UROHWI9cRtbK9u4Nn4yvf\/Q7P\/fwJrl9ZYV5aanRElF46XURX6vdQToopuAyWqG1Bau3PoQDEEHHUEskcVSOZM0iZkTtff+zzfPrh0+xc3uaJHz5O1iHrowE333Idu5sX2Zzsce+3v0xSoZ59kw8d2WBnOmGvm1NqR6ktaCW5YSa4K8mFlAyX0Qoy76BUAvo9giKSUDHEE1mdQUqMUuKRR+\/j0w+fBuAvT79AomG8PGZ51LB9acrxj3+U+x+6Cx80PPu9H7NxYBWNls2toOsSJXpAIRXVIGXHXUhJ8Sy4DMeQOyggoRCKoCAOmjB1kjk5JU6dOsFnv3jPtZSwdX6H\/YcOcvT4BsdP3sANt9\/E0oEVIoI3fvUUS8NMqcsMmo7cVJBKjZaumxO1RQ1UA3MjN44nwRmvQleIkB5M9NFlOK4JxZHFAfjoNx+8djIDPPCN+\/jPEhGce+p55hcucvDG\/cw2M+3uFVa0RawiFtTaUrsZQoeaYK6knPGmwXU8JhX6PIPioSSMLE4OI6uRUW4\/dYyjR\/f9F4B\/L7UUXv31H9h+5VUGS8pgdcTB266n21xi621BZY7QgmSiJERqH2HJsZyxZoiP18aUAiwYMgQPZyDGAGWA0VThzk\/c8n\/B7FzY5KVfPMP8vQsMG0ChnU6YvNfiMme02lDb0p89BioJWcil7lgeoM0QP7xvSNcFtUANRUNRjBRCwhiE0hTh1psO\/E8g060Jf3\/6Bc798WWytAwHtU8dFaKFOjNolDxUIikmsZApoaZYymhukNRAHuIf3miY7LXMZ4V5VymlUmpFQpCoWBFMhAPro2sgdnemnH3lHGf+\/BrnXvwnTbSMvBCp4FSyVkIDLGDe50pJQfLATTATNCUkDyAZ5Ay5AR\/gD62\/xe5eZWenZWu3stMF2zOYzGGvhXknlA5+9IOfMN2dcuXiFruXtsilkCgkKgOtDK1jKQUrg8p8VGEcpBAG1tsMKS3qgWXDatC2hjGmnRk6SGxeHtEyQE6fPBArg8TeXm+V3DIhTsUJSRScqpmNw9dx\/uJFutI7AVejaRrWxsvMJlOyCY3C+nJmnIPVNOfIeuHEiXWo27z+9hV2plNKblm77ihP\/ub3nHl7xsqgsrExZtYGz760iz93rqIpEFUsGd4kRA3PDZ4ylhpUjdP3fIr5Sy9zcH0N1IlQjmwc4sKFyxxcX8VDmE+mnPzgCRoRdi+8yygHZd8Yn13iUPc611vH2lLHradG3HPTMS68vcV4CC4dB++8j8lff4vc8dXHolleoaswWBrjqUHVEXOSJ0QMAa7fv8YwJdZGDRcvbTNKjtTKbDrjwHjEZHePaDuWkhN7Mw6vLjFSWM7KQAvtlQtkq6yOKredXKNZgteef43xUGi8Y3joEHllFS8YO5MpWGK+vY3ILqC9F4regKsol997FykVSkVqpe7tQS1kM6QEEoHVQqL3xqOUGSdn7M5qkxglwbUwyrCz13LHR1Z487JSL3WsDGF85S0+8MDH8Mtn\/8G8bVHP1FLxZgjv\/0MggKeEqiIRRA00egBaK9J11wx+bWe4GFfOv84gD3ARVpdX2L+yhkdlMtlifWXMn1523jk75PzmHmfe22OYg0bnfKZ7Ezlw821RS6Gbz6ntjLQ0RkIo8z00NX06qB2eBwC95wa0BoogcdVD915cIxAqJoKr4AJKJZuhGnRdi1DYGDurA+PStLe5jcOdx+FfEghCLeMqGgkAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-function-mock_big.png\u0022 alt=\u0022Avris FunctionMock\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFunctionMock is a simple and elegant way to mock away system\/global functions in your tests.\u003C\/p\u003E\n\u003Ch3\u003EInstalation\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs bash border\u0022\u003Ecomposer require --dev avris\/\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E-mock\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EUsage\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s say you have a class that writes something to a file:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Enamespace\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EApp\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003EService\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EWorkService\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Ework\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E(int $input)\u003C\/span\u003E: \u003Cspan class=\u0022hljs-title\u0022\u003Ebool\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $result = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027correctResult\u0027\u003C\/span\u003E; \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ ... calculate the result somehow\u003C\/span\u003E\n\n        $filename = \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/tmp\/foo\u0027\u003C\/span\u003E;\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E file_put_contents($filename, $result);\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETo test it, without actually using filesystem, you can use FunctionMock:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E\u003Cspan class=\u0022hljs-meta\u0022\u003E\u0026lt;?php\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Enamespace\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EApp\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003ETest\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Euse\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EApp\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003EService\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003EWorkService\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-title\u0022\u003Euse\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EPHPUnit\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003EFramework\u003C\/span\u003E\\\u003Cspan class=\u0022hljs-title\u0022\u003ETestCase\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-class\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eclass\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EServiceTest\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eextends\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003ETestCase\u003C\/span\u003E\n\u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-comment\u0022\u003E\/** \u003Cspan class=\u0022hljs-doctag\u0022\u003E@var\u003C\/span\u003E WorkService *\/\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprivate\u003C\/span\u003E $service;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprotected\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EsetUp\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;service = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E WorkService();\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eprotected\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EtearDown\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        FunctionMock::clean();\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Epublic\u003C\/span\u003E \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003EtestWork\u003C\/span\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E\n    \u003C\/span\u003E{\n        $mock = FunctionMock::create(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027App\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027file_put_contents\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E);\n\n        $returnValue = \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;service-\u0026gt;work(\u003Cspan class=\u0022hljs-number\u0022\u003E8\u003C\/span\u003E);\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;assertTrue($returnValue);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003E$this\u003C\/span\u003E-\u0026gt;assertEquals([[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/tmp\/foo\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027correctResult\u0027\u003C\/span\u003E]], $mock-\u0026gt;getInvocations());\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf your tests are in the same namespace with your tested classes, it\u2019s recommended to use \u003Ccode\u003E__NAMESPACE__\u003C\/code\u003E. \u003C\/p\u003E\n\u003Cp\u003EThe third parameter, the return value of the mocked function, can either be a literal or a callable:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$mock = FunctionMock::create(\u003Cspan class=\u0022hljs-keyword\u0022\u003E__NAMESPACE__\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027file_put_contents\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-params\u0022\u003E($filename, $data)\u003C\/span\u003E \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $filename === \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/tmp\/foo\u0027\u003C\/span\u003E;\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EYou can disable\/re-enable the mock by invoking \u003Ccode\u003E$mock-\u0026gt;disable()\u003C\/code\u003E and \u003Ccode\u003E$mock-\u0026gt;enable()\u003C\/code\u003E,\nas well as clear the list of logged invocations with \u003Ccode\u003E$mock-\u0026gt;clearInvocations()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Ch3\u003EKnown limitations\u003C\/h3\u003E\n\u003Cp\u003EFunctionMock works thanks to the fact that \u003Ccode\u003Efile_get_contents\u003C\/code\u003E inside of \u003Ccode\u003EApp\\Service\u003C\/code\u003E namespace references to the function\n\u003Ccode\u003EApp\\Service\\file_get_contents\u003C\/code\u003E and only if it\u2019s not defined it falls back to the global \u003Ccode\u003E\\file_get_contents\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EFunctionMock defines this \u003Ccode\u003EApp\\Service\\file_get_contents\u003C\/code\u003E function on the fly\nand makes it adjustable to your needs in the runtime.\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EIf you already have invoked \u003Ccode\u003Efile_get_contents\u003C\/code\u003E inside of \u003Ccode\u003EApp\\Service\u003C\/code\u003E before registering a mock,\nPHP will continue using the global function and it cannot be overwritten anymore.\u003C\/li\u003E\n\u003Cli\u003EIf you\u2019re using \u003Ccode\u003E\\file_get_contents\u003C\/code\u003E (explicitly global namespace) inside your tested class,\nthere\u2019s obviously no way to mock it.\u003C\/li\u003E\n\u003Cli\u003EAfter being registered, mock function cannot be really unset, only disabled.\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["function","global function","mock","namespaces","php","tests"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-function-mock_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-function-mock_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-function-mock_mini.png\u0022 alt=\u0022Avris FunctionMock\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFunctionMock is a simple and elegant way to mock away system\/global functions in your tests.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-function-mock_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-function-mock_mini.png\u0022 alt=\u0022Avris FunctionMock\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFunctionMock is a simple and elegant way to mock away system\/global functions in your tests.\u003C\/p\u003E\n\u003Ch3\u003EInstalation\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-bash\u0022\u003Ecomposer require --dev avris\/function-mock\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EUsage\u003C\/h3\u003E\n\u003Cp\u003ELet\u2019s say you have a class that writes something to a file:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E\u0026lt;?php\nnamespace App\\Service;\n\nclass WorkService\n{\n    public function work(int $input): bool\n    {\n        $result = \u0027correctResult\u0027; \/\/ ... calculate the result somehow\n\n        $filename = \u0027\/tmp\/foo\u0027;\n\n        return file_put_contents($filename, $result);\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETo test it, without actually using filesystem, you can use FunctionMock:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E\u0026lt;?php\nnamespace App\\Test;\n\nuse App\\Service\\WorkService\nuse PHPUnit\\Framework\\TestCase;\n\nclass ServiceTest extends TestCase\n{\n    \/** @var WorkService *\/\n    private $service;\n\n    protected function setUp()\n    {\n        $this-\u0026gt;service = new WorkService();\n    }\n\n    protected function tearDown()\n    {\n        FunctionMock::clean();\n    }\n\n    public function testWork()\n    {\n        $mock = FunctionMock::create(\u0027App\u0027, \u0027file_put_contents\u0027, true);\n\n        $returnValue = $this-\u0026gt;service-\u0026gt;work(8);\n\n        $this-\u0026gt;assertTrue($returnValue);\n        $this-\u0026gt;assertEquals([[\u0027\/tmp\/foo\u0027, \u0027correctResult\u0027]], $mock-\u0026gt;getInvocations());\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIf your tests are in the same namespace with your tested classes, it\u2019s recommended to use \u003Ccode\u003E__NAMESPACE__\u003C\/code\u003E. \u003C\/p\u003E\n\u003Cp\u003EThe third parameter, the return value of the mocked function, can either be a literal or a callable:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$mock = FunctionMock::create(__NAMESPACE__, \u0027file_put_contents\u0027, function ($filename, $data) {\n    return $filename === \u0027\/tmp\/foo\u0027;\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EYou can disable\/re-enable the mock by invoking \u003Ccode\u003E$mock-\u0026gt;disable()\u003C\/code\u003E and \u003Ccode\u003E$mock-\u0026gt;enable()\u003C\/code\u003E,\nas well as clear the list of logged invocations with \u003Ccode\u003E$mock-\u0026gt;clearInvocations()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Ch3\u003EKnown limitations\u003C\/h3\u003E\n\u003Cp\u003EFunctionMock works thanks to the fact that \u003Ccode\u003Efile_get_contents\u003C\/code\u003E inside of \u003Ccode\u003EApp\\Service\u003C\/code\u003E namespace references to the function\n\u003Ccode\u003EApp\\Service\\file_get_contents\u003C\/code\u003E and only if it\u2019s not defined it falls back to the global \u003Ccode\u003E\\file_get_contents\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EFunctionMock defines this \u003Ccode\u003EApp\\Service\\file_get_contents\u003C\/code\u003E function on the fly\nand makes it adjustable to your needs in the runtime.\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EIf you already have invoked \u003Ccode\u003Efile_get_contents\u003C\/code\u003E inside of \u003Ccode\u003EApp\\Service\u003C\/code\u003E before registering a mock,\nPHP will continue using the global function and it cannot be overwritten anymore.\u003C\/li\u003E\n\u003Cli\u003EIf you\u2019re using \u003Ccode\u003E\\file_get_contents\u003C\/code\u003E (explicitly global namespace) inside your tested class,\nthere\u2019s obviously no way to mock it.\u003C\/li\u003E\n\u003Cli\u003EAfter being registered, mock function cannot be really unset, only disabled.\u003C\/li\u003E\n\u003C\/ul\u003E","words":346,"readTime":2,"lang":"en"}}}}}