-
Notifications
You must be signed in to change notification settings - Fork 461
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #731 from mockery/documentation/issue442
Documentation updates
- Loading branch information
Showing
36 changed files
with
1,710 additions
and
693 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
.. 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
.. index:: | ||
single: Cookbook; Class Constants | ||
|
||
Class Constants | ||
=============== | ||
|
||
When creating a test double for a class, Mockery does not create stubs out of | ||
any class contants 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 contants in Mockery would be possible, it does require | ||
an awful lot of work, for a small number of use cases. | ||
|
||
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::mock('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); | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
* :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` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
.. 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 print "Original constructor called." | ||
$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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,5 +7,6 @@ Getting Started | |
installation | ||
upgrading | ||
simple_example | ||
quick_reference | ||
|
||
.. include:: map.rst.inc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
* :doc:`/getting_started/installation` | ||
* :doc:`/getting_started/upgrading` | ||
* :doc:`/getting_started/simple_example` | ||
* :doc:`/getting_started/quick_reference` |
Oops, something went wrong.