Mocking with Phake
First published at Wednesday 13 March 2013
Warning: This blog post is more then 11 years old – read and use with care.
Mocking with Phake
Update (14.3.2013): Introduced Test Double wording instead of using mock objects for everything to more cleanly describe the different concepts.
The use of Test Doubles is an important skill to learn when using Test Driven Development (TDD). Test Doubles allow you to replace dependencies of an object with lookalikes, much like crash test dummies are used during automobile safety tests so humans aren't harmed.
Test Doubles Explained
Creating a test double in PHP involves creating a new class that extends the public API of the original class with empty methods. You can safely use all methods of a test double and they will do nothing, rather than calling the original code of the original class. There are two ways to create these test doubles: You can write them yourself or use one of the many existing libraries.
I would strongly recommend to use any of the existing libraries that can simplify and automate this task for you. Technically they work using code-generation at run-time.
To allow interactions with test doubles there are three ways to configure them in any library:
Add expectations of the arguments passed to a method (Verification)
Add results that are returned from a method-call to the mock object (Stubbing)
Delegate calls to the original code (Spying)
Test doubles using the first approach are called Mock Objects. Objects of the second type are called Stubs, of the third type Spies.
Benefits of Test Doubles
There are many reasons why test doubles are useful:
Allow units (objects) to be tested in isolation of their dependencies. This is done by replacing the dependencies with test doubles.
Allow verification of behavior between objects. In contrast to assertions that can only verify the state of objects in isolation. This makes them very useful with relation to Behavior Driven Development (BDD) inside your unit-tests.
Test Doubles are useful to test-drive new interfaces based on required behavior without caring for the implementation at the moment.
That means testdoubles are invaluable to move from state-based object-oriented programming to a behavioral approach based on sending messages between objects.
Introduction to Phake
Using Test Doubles in PHPUnit tests means using the built-in MockObjects library for quite some years. In the last years two contenders emerged that can be used as optional dependencies in PHPUnit:
Both can be installed using Composer and integrated into your projects very easily.
This blog post introduces Phake, because it works quite differently than both PHPUnit Mock Objects and Mockery:
In the well known four phase test with Setup, Exercise, Verify, Teardown both PHPUnit mocks and Mockery require expectations to be part of the "setup" phase.
This is unfortunate, because mock expectations are much more related to the "Verify" phase instead. This happens in PHPUnit and Mockery, because they don't explicitly differentiate between methods that are mocked (verification) or stubbed (returning results). Phake introduces a differentiation by requiring different APIs to be used for configuration.
Instead of using strings for method names and builder methods for arguments, Phake let's you prototype the method-call in actual PHP code. This simplifies the mock object configuration considerably and requires much less typing.
Let's see an example containing both mock and stub objects in one test for loading the weather data for a given location.
<?php
class LoaderTest extends \PHPUnit_Framework_TestCase
{
public function testGetWeather()
{
// 1. setup
$logger = \Phake::mock('Qafoo\\Weather\\Logger');
$functional = \Phake::mock('Qafoo\\Weather\\Service');
// Stubbing with Phake::when()
\Phake::when($functional)->getWeatherForLocation()->thenReturn(
new Struct\Weather( 'Fair', 23, 0, 'NW' )
);
$loader = new Loader($functional, $logger);
// 2. exercise
$locatedWeather = $loader->getWeatherForLocation(
new Struct\Location( 'Berlin', 'Germany' )
);
// 3. verify
$this->assertInstanceOf(
'Qafoo\\Weather\\Struct\\LocatedWeather',
$locatedWeather
);
// Verification with Phake::verify()
\Phake::verify($logger)->log('Fetched weather for Berlin Germany.');
}
}
Using the Phake::when()
call and passing a mock object you can prototype what a method call should return for your code to show a desired behavior. See how we can just call ->getWeatherForLocation()
as a prototype for how the stub behaves instead of PHPUnits ->method('getWeatherForLocation')
or Mockerys ->shouldRecieve('getWeatherForLocation')
.
Using thenReturn
specifies the return value of this method call and completes the description of how the stub works. If you want to return different values on consecutive calls, just chain multiple thenReturn
calls. You can use thenThrow
to throw exceptions.
Verification is done with Phake::verify()
after the tested code was actually exercised. We again prototype what method calls and which arguments we want to verify, in this case ->log('Fetched weather for
Berlin Germany');
on the logger mock.
This is a very simple stubbing and verification example with Phake. Comparable to PHPUnit and Mockery, we could add more complex expectations:
Using argument matchers to verify the structure of arguments used in method calls.
Checking multiple invocations such as exactly n-times, at least N-times or others.
Verify no interaction with a mock happened at all.
Verify no further interaction happened than the ones already verified.
Conclusion
Phake is a great mocking library and can be easily integrated into PHPUnit. Its new approach to prototype mocks and stubs and the separation between stubbing and verification phases is very refreshing and easy to use.
If you want to go into more detail and learn about Phake, you should check out the extensive documentation.
Subscribe to updates
There are multiple ways to stay updated with new posts on my blog: