One Hat Cyber Team
Your IP:
216.73.216.102
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
home
/
fluxyjvi
/
www
/
assets
/
images
/
Edit File:
cookbook.tar
big_parent_class.rst 0000644 00000003210 15107320326 0010570 0 ustar 00 .. index:: single: Cookbook; Big Parent Class Big Parent Class ================ In some application code, especially older legacy code, we can come across some classes that extend a "big parent class" - a parent class that knows and does too much: .. code-block:: php class BigParentClass { public function doesEverything() { // sets up database connections // writes to log files } } class ChildClass extends BigParentClass { public function doesOneThing() { // but calls on BigParentClass methods $result = $this->doesEverything(); // does something with $result return $result; } } We want to test our ``ChildClass`` and its ``doesOneThing`` method, but the problem is that it calls on ``BigParentClass::doesEverything()``. One way to handle this would be to mock out **all** of the dependencies ``BigParentClass`` has and needs, and then finally actually test our ``doesOneThing`` method. It's an awful lot of work to do that. What we can do, is to do something... unconventional. We can create a runtime partial test double of the ``ChildClass`` itself and mock only the parent's ``doesEverything()`` method: .. code-block:: php $childClass = \Mockery::mock('ChildClass')->makePartial(); $childClass->shouldReceive('doesEverything') ->andReturn('some result from parent'); $childClass->doesOneThing(); // string("some result from parent"); With this approach we mock out only the ``doesEverything()`` method, and all the unmocked methods are called on the actual ``ChildClass`` instance. map.rst.inc 0000644 00000000423 15107320326 0006621 0 ustar 00 * :doc:`/cookbook/default_expectations` * :doc:`/cookbook/detecting_mock_objects` * :doc:`/cookbook/not_calling_the_constructor` * :doc:`/cookbook/mocking_hard_dependencies` * :doc:`/cookbook/class_constants` * :doc:`/cookbook/big_parent_class` * :doc:`/cookbook/mockery_on` mocking_class_within_class.rst 0000644 00000010475 15107320326 0012667 0 ustar 00 .. index:: single: Cookbook; Mocking class within class .. _mocking-class-within-class: Mocking class within class ========================== Imagine a case where you need to create an instance of a class and use it within the same method: .. code-block:: php // Point.php <?php namespace App; class Point { public function setPoint($x, $y) { echo "Point (" . $x . ", " . $y . ")" . PHP_EOL; } } // Rectangle.php <?php namespace App; use App\Point; class Rectangle { public function create($x1, $y1, $x2, $y2) { $a = new Point(); $a->setPoint($x1, $y1); $b = new Point(); $b->setPoint($x2, $y1); $c = new Point(); $c->setPoint($x2, $y2); $d = new Point(); $d->setPoint($x1, $y2); $this->draw([$a, $b, $c, $d]); } public function draw($points) { echo "Do something with the points"; } } And that you want to test that a logic in ``Rectangle->create()`` calls properly each used thing - in this case calls ``Point->setPoint()``, but ``Rectangle->draw()`` does some graphical stuff that you want to avoid calling. You set the mocks for ``App\Point`` and ``App\Rectangle``: .. code-block:: php <?php class MyTest extends PHPUnit\Framework\TestCase { public function testCreate() { $point = Mockery::mock("App\Point"); // check if our mock is called $point->shouldReceive("setPoint")->andThrow(Exception::class); $rect = Mockery::mock("App\Rectangle")->makePartial(); $rect->shouldReceive("draw"); $rect->create(0, 0, 100, 100); // does not throw exception Mockery::close(); } } and the test does not work. Why? The mocking relies on the class not being present yet, but the class is autoloaded therefore the mock alone for ``App\Point`` is useless which you can see with ``echo`` being executed. Mocks however work for the first class in the order of loading i.e. ``App\Rectangle``, which loads the ``App\Point`` class. In more complex example that would be a single point that initiates the whole loading (``use Class``) such as:: A // main loading initiator |- B // another loading initiator | |-E | +-G | |- C // another loading initiator | +-F | +- D That basically means that the loading prevents mocking and for each such a loading initiator there needs to be implemented a workaround. Overloading is one approach, however it pollutes the global state. In this case we try to completely avoid the global state pollution with custom ``new Class()`` behavior per loading initiator and that can be mocked easily in few critical places. That being said, although we can't stop loading, we can return mocks. Let's look at ``Rectangle->create()`` method: .. code-block:: php class Rectangle { public function newPoint() { return new Point(); } public function create($x1, $y1, $x2, $y2) { $a = $this->newPoint(); $a->setPoint($x1, $y1); ... } ... } We create a custom function to encapsulate ``new`` keyword that would otherwise just use the autoloaded class ``App\Point`` and in our test we mock that function so that it returns our mock: .. code-block:: php <?php class MyTest extends PHPUnit\Framework\TestCase { public function testCreate() { $point = Mockery::mock("App\Point"); // check if our mock is called $point->shouldReceive("setPoint")->andThrow(Exception::class); $rect = Mockery::mock("App\Rectangle")->makePartial(); $rect->shouldReceive("draw"); // pass the App\Point mock into App\Rectangle as an alternative // to using new App\Point() in-place. $rect->shouldReceive("newPoint")->andReturn($point); $this->expectException(Exception::class); $rect->create(0, 0, 100, 100); Mockery::close(); } } If we run this test now, it should pass. For more complex cases we'd find the next loader in the program flow and proceed with wrapping and passing mock instances with predefined behavior into already existing classes. mocking_hard_dependencies.rst 0000644 00000010570 15107320326 0012433 0 ustar 00 .. index:: single: Cookbook; Mocking Hard Dependencies Mocking Hard Dependencies (new Keyword) ======================================= One prerequisite to mock hard dependencies is that the code we are trying to test uses autoloading. Let's take the following code for an example: .. code-block:: php <?php namespace App; class Service { function callExternalService($param) { $externalService = new Service\External($version = 5); $externalService->sendSomething($param); return $externalService->getSomething(); } } The way we can test this without doing any changes to the code itself is by creating :doc:`instance mocks </reference/instance_mocking>` by using the ``overload`` prefix. .. code-block:: php <?php namespace AppTest; use Mockery as m; class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $param = 'Testing'; $externalMock = m::mock('overload:App\Service\External'); $externalMock->shouldReceive('sendSomething') ->once() ->with($param); $externalMock->shouldReceive('getSomething') ->once() ->andReturn('Tested!'); $service = new \App\Service(); $result = $service->callExternalService($param); $this->assertSame('Tested!', $result); } } If we run this test now, it should pass. Mockery does its job and our ``App\Service`` will use the mocked external service instead of the real one. The problem with this is when we want to, for example, test the ``App\Service\External`` itself, or if we use that class somewhere else in our tests. When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a "class already exists" exception. This is where autoloading kicks in and makes our job a lot easier. To make this possible, we'll tell PHPUnit to run the tests that have overloaded classes in separate processes and to not preserve global state. That way we'll avoid having the overloaded class included more than once. Of course this has its downsides as these tests will run slower. Our test example from above now becomes: .. code-block:: php <?php namespace AppTest; use Mockery as m; /** * @runTestsInSeparateProcesses * @preserveGlobalState disabled */ class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $param = 'Testing'; $externalMock = m::mock('overload:App\Service\External'); $externalMock->shouldReceive('sendSomething') ->once() ->with($param); $externalMock->shouldReceive('getSomething') ->once() ->andReturn('Tested!'); $service = new \App\Service(); $result = $service->callExternalService($param); $this->assertSame('Tested!', $result); } } Testing the constructor arguments of hard Dependencies ------------------------------------------------------ Sometimes we might want to ensure that the hard dependency is instantiated with particular arguments. With overloaded mocks, we can set up expectations on the constructor. .. code-block:: php <?php namespace AppTest; use Mockery as m; /** * @runTestsInSeparateProcesses * @preserveGlobalState disabled */ class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $externalMock = m::mock('overload:App\Service\External'); $externalMock->allows('sendSomething'); $externalMock->shouldReceive('__construct') ->once() ->with(5); $service = new \App\Service(); $result = $service->callExternalService($param); } } .. note:: For more straightforward and single-process tests oriented way check :ref:`mocking-class-within-class`. .. note:: This cookbook entry is an adaption of the blog post titled `"Mocking hard dependencies with Mockery" <https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/>`_, published by Robert Basic on his blog. index.rst 0000644 00000000421 15107320326 0006401 0 ustar 00 Cookbook ======== .. toctree:: :hidden: default_expectations detecting_mock_objects not_calling_the_constructor mocking_hard_dependencies class_constants big_parent_class mockery_on mocking_class_within_class .. include:: map.rst.inc default_expectations.rst 0000644 00000001365 15107320326 0011514 0 ustar 00 .. index:: single: Cookbook; Default Mock Expectations Default Mock Expectations ========================= Often in unit testing, we end up with sets of tests which use the same object dependency over and over again. Rather than mocking this class/object within every single unit test (requiring a mountain of duplicate code), we can instead define reusable default mocks within the test case's ``setup()`` method. This even works where unit tests use varying expectations on the same or similar mock object. How this works, is that you can define mocks with default expectations. Then, in a later unit test, you can add or fine-tune expectations for that specific test. Any expectation can be set as a default using the ``byDefault()`` declaration. class_constants.rst 0000644 00000011104 15107320326 0010473 0 ustar 00 .. index:: single: Cookbook; Class Constants Class Constants =============== When creating a test double for a class, Mockery does not create stubs out of any class constants defined in the class we are mocking. Sometimes though, the non-existence of these class constants, setup of the test, and the application code itself, it can lead to undesired behavior, and even a PHP error: ``PHP Fatal error: Uncaught Error: Undefined class constant 'FOO' in ...`` While supporting class constants in Mockery would be possible, it does require an awful lot of work, for a small number of use cases. Named Mocks ----------- We can, however, deal with these constants in a way supported by Mockery - by using :ref:`creating-test-doubles-named-mocks`. A named mock is a test double that has a name of the class we want to mock, but under it is a stubbed out class that mimics the real class with canned responses. Lets look at the following made up, but not impossible scenario: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public static function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } class MyClass { public function doFetching() { $response = Fetcher::fetch(); if ($response == Fetcher::SUCCESS) { echo "Thanks!" . PHP_EOL; } else { echo "Try again!" . PHP_EOL; } } } Our ``MyClass`` calls a ``Fetcher`` that fetches some resource from somewhere - maybe it downloads a file from a remote web service. Our ``MyClass`` prints out a response message depending on the response from the ``Fetcher::fetch()`` call. When testing ``MyClass`` we don't really want ``Fetcher`` to go and download random stuff from the internet every time we run our test suite. So we mock it out: .. code-block:: php // Using alias: because fetch is called statically! \Mockery::mock('alias:Fetcher') ->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching(); If we run this, our test will error out with a nasty ``PHP Fatal error: Uncaught Error: Undefined class constant 'SUCCESS' in ..``. Here's how a ``namedMock()`` can help us in a situation like this. We create a stub for the ``Fetcher`` class, stubbing out the class constants, and then use ``namedMock()`` to create a mock named ``Fetcher`` based on our stub: .. code-block:: php class FetcherStub { const SUCCESS = 0; const FAILURE = 1; } \Mockery::namedMock('Fetcher', 'FetcherStub') ->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching(); This works because under the hood, Mockery creates a class called ``Fetcher`` that extends ``FetcherStub``. The same approach will work even if ``Fetcher::fetch()`` is not a static dependency: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } class MyClass { public function doFetching($fetcher) { $response = $fetcher->fetch(); if ($response == Fetcher::SUCCESS) { echo "Thanks!" . PHP_EOL; } else { echo "Try again!" . PHP_EOL; } } } And the test will have something like this: .. code-block:: php class FetcherStub { const SUCCESS = 0; const FAILURE = 1; } $mock = \Mockery::mock('Fetcher', 'FetcherStub') $mock->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching($mock); Constants Map ------------- Another way of mocking class constants can be with the use of the constants map configuration. Given a class with constants: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } It can be mocked with: .. code-block:: php \Mockery::getConfiguration()->setConstantsMap([ 'Fetcher' => [ 'SUCCESS' => 'success', 'FAILURE' => 'fail', ] ]); $mock = \Mockery::mock('Fetcher'); var_dump($mock::SUCCESS); // (string) 'success' var_dump($mock::FAILURE); // (string) 'fail' detecting_mock_objects.rst 0000644 00000000612 15107320326 0011764 0 ustar 00 .. index:: single: Cookbook; Detecting Mock Objects Detecting Mock Objects ====================== Users may find it useful to check whether a given object is a real object or a simulated Mock Object. All Mockery mocks implement the ``\Mockery\MockInterface`` interface which can be used in a type check. .. code-block:: php assert($mightBeMocked instanceof \Mockery\MockInterface); mockery_on.rst 0000644 00000005753 15107320326 0007454 0 ustar 00 .. index:: single: Cookbook; Complex Argument Matching With Mockery::on Complex Argument Matching With Mockery::on ========================================== When we need to do a more complex argument matching for an expected method call, the ``\Mockery::on()`` matcher comes in really handy. It accepts a closure as an argument and that closure in turn receives the argument passed in to the method, when called. If the closure returns ``true``, Mockery will consider that the argument has passed the expectation. If the closure returns ``false``, or a "falsey" value, the expectation will not pass. The ``\Mockery::on()`` matcher can be used in various scenarios — validating an array argument based on multiple keys and values, complex string matching... Say, for example, we have the following code. It doesn't do much; publishes a post by setting the ``published`` flag in the database to ``1`` and sets the ``published_at`` to the current date and time: .. code-block:: php <?php namespace Service; class Post { public function __construct($model) { $this->model = $model; } public function publishPost($id) { $saveData = [ 'post_id' => $id, 'published' => 1, 'published_at' => gmdate('Y-m-d H:i:s'), ]; $this->model->save($saveData); } } In a test we would mock the model and set some expectations on the call of the ``save()`` method: .. code-block:: php <?php $postId = 42; $modelMock = \Mockery::mock('Model'); $modelMock->shouldReceive('save') ->once() ->with(\Mockery::on(function ($argument) use ($postId) { $postIdIsSet = isset($argument['post_id']) && $argument['post_id'] === $postId; $publishedFlagIsSet = isset($argument['published']) && $argument['published'] === 1; $publishedAtIsSet = isset($argument['published_at']); return $postIdIsSet && $publishedFlagIsSet && $publishedAtIsSet; })); $service = new \Service\Post($modelMock); $service->publishPost($postId); \Mockery::close(); The important part of the example is inside the closure we pass to the ``\Mockery::on()`` matcher. The ``$argument`` is actually the ``$saveData`` argument the ``save()`` method gets when it is called. We check for a couple of things in this argument: * the post ID is set, and is same as the post ID we passed in to the ``publishPost()`` method, * the ``published`` flag is set, and is ``1``, and * the ``published_at`` key is present. If any of these requirements is not satisfied, the closure will return ``false``, the method call expectation will not be met, and Mockery will throw a ``NoMatchingExpectationException``. .. note:: This cookbook entry is an adaption of the blog post titled `"Complex argument matching in Mockery" <https://robertbasic.com/blog/complex-argument-matching-in-mockery/>`_, published by Robert Basic on his blog. not_calling_the_constructor.rst 0000644 00000004150 15107320326 0013073 0 ustar 00 .. index:: single: Cookbook; Not Calling the Original Constructor Not Calling the Original Constructor ==================================== When creating generated partial test doubles, Mockery mocks out only the method which we specifically told it to. This means that the original constructor of the class we are mocking will be called. In some cases this is not a desired behavior, as the constructor might issue calls to other methods, or other object collaborators, and as such, can create undesired side-effects in the application's environment when running the tests. If this happens, we need to use runtime partial test doubles, as they don't call the original constructor. .. code-block:: php class MyClass { public function __construct() { echo "Original constructor called." . PHP_EOL; // Other side-effects can happen... } } // This will print "Original constructor called." $mock = \Mockery::mock('MyClass[foo]'); A better approach is to use runtime partial doubles: .. code-block:: php class MyClass { public function __construct() { echo "Original constructor called." . PHP_EOL; // Other side-effects can happen... } } // This will not print anything $mock = \Mockery::mock('MyClass')->makePartial(); $mock->shouldReceive('foo'); This is one of the reason why we don't recommend using generated partial test doubles, but if possible, always use the runtime partials. Read more about :ref:`creating-test-doubles-partial-test-doubles`. .. note:: The way generated partial test doubles work, is a BC break. If you use a really old version of Mockery, it might behave in a way that the constructor is not being called for these generated partials. In the case if you upgrade to a more recent version of Mockery, you'll probably have to change your tests to use runtime partials, instead of generated ones. This change was introduced in early 2013, so it is highly unlikely that you are using a Mockery from before that, so this should not be an issue.
Simpan