Method Stubbing¶
The Phake::when()
method is used to stub methods in Phake. As discussed in the introduction,
stubbing allows an object method to be forced to return a particular value given a set of parameters. Similarly to
Phake::verify()
, Phake::when()
accepts a mock object generated from
Phake::mock()
as its first parameter.
Imagine I was in the process of building the next great online shopping cart. The first thing any good shopping cart allows is to be able to add items. The most important thing I want to know from the shopping cart is how much money in merchandise is in there. So, I need to make myself a ShoppingCart class. I also am going to need some class to define my items. I am more worried about the money right now and because of that I am keenly aware that any item in a shopping cart is going to have a price. So I will just create an interface to represent those items called Item. Now take a minute to marvel at the creativity of those names. Great, now check out the initial definitions for my objects.
/**
* An item that is going to make me rich.
*/
interface Item
{
/**
* @return money
*/
public function getPrice();
}
/**
* A customer's cart that will contain items that are going to make me rich.
*/
class ShoppingCart
{
private $items = array();
/**
* Adds an item to the customer's order
* @param Item $item
*/
public function addItem(Item $item)
{
$this->items[] = $item;
}
/**
* Returns the current sub total of the customer's order
* @return money
*/
public function getSubTotal()
{
}
}
So, I am furiously coding away at this fantastic new ShoppingCart
class when I
realize, I am doing it wrong! You see, a few years ago I went to this conference with a bunch of
other geeky people to talk about how to make quality software. I am supposed to be writing unit
tests. Here I am, a solid thirteen lines (not counting comments) of code into my awe inspiring
new software and I haven’t written a single test. I tell myself, “There’s no better time to change
than right now!” So I decide to start testing. After looking at the options I decide PHPUnit with
this sweet new mock library called Phake is the way to go.
My first test is going to be for the currently unimplemented ShoppingCart::getSubTotal()
method. I already have a pretty good idea of what this function is going to need to do. It will
need to look at all of the items in the cart, retrieve their price, add it all together and return
the result. So, in my test I know I am going to need a fixture that sets up a shopping cart with
a few items added. Then I am going to need a test that calls ShoppingCart::getSubTotal()
and asserts that it returns a value equal to the price of the items I added to the cart. One catch
though, I don’t have any concrete instances of an Item
. I wasn’t even planning on doing any of
that until tomorrow. I really want to just focus on the ShoppingCart
class.
Never fear, this is why I decided to use Phake. I remember reading about how it will allow me to
quickly create instance of my classes and interfaces that I can set up stubs for so that method
calls return predictable values. This project is all coming together and I am really excited.
class ShoppingCartTest extends PHPUnit_Framework_TestCase
{
private $shoppingCart;
private $item1;
private $item2;
private $item3;
public function setUp()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
Phake::when($this->item1)->getPrice()->thenReturn(100);
Phake::when($this->item2)->getPrice()->thenReturn(200);
Phake::when($this->item3)->getPrice()->thenReturn(300);
$this->shoppingCart = new ShoppingCart();
$this->shoppingCart->addItem($this->item1);
$this->shoppingCart->addItem($this->item2);
$this->shoppingCart->addItem($this->item3);
}
public function testGetSub()
{
$this->assertEquals(600, $this->shoppingCart->getSubTotal());
}
}
My test here shows a very basic use of Phake for creating method stubs. I am creating three different mock
implementations of the Item
class. Then for each of those item classes, I am creating
a stub using Phake::when()
that will return 100, 200, and 300 respectively. I know my method
that I am getting ready to implement will need to call those methods in order to calculate the total cost of the
order.
My test is written so now it is time to see how it fails. I run it with phpunit and see the output below:
$ phpunit ExampleTests/ShoppingCartTest.php
PHPUnit 3.5.13 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 8.50Mb
There was 1 failure:
1) ShoppingCartTest::testGetSub
Failed asserting that <null> matches expected <integer:600>.
/home/mikel/Documents/Projects/Phake/tests/ShoppingCartTest.php:69
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Generating code coverage report, this may take a moment.
Now that I have a working (and I by working I mean breaking!) test it is time to look at the code necessary to make the test pass.
class ShoppingCart
{
// I am cutting out the already seen code. If you want to see it again look at the previous examples!
/**
* Returns the current sub total of the customer's order
* @return money
*/
public function getSubTotal()
{
$total = 0;
foreach ($this->items as $item)
{
$total += $item->getPrice();
}
return $total;
}
}
The code here is pretty simple. I am just iterating over the ShoppingCart::$item
property,
calling the Item::getPrice()
method, and adding them all together. Now when I run phpunit, the tests were successful
and I am getting off to a great start with my shopping cart.
$ phpunit ExampleTests/ShoppingCartTest.php
PHPUnit 3.5.13 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 8.25Mb
OK (1 test, 1 assertion)
Generating code coverage report, this may take a moment.
So, what is Phake doing here? Phake is providing us a predictable implementation of the Item::getPrice()
method that we can use in our test. It helps me to ensure the when my test breaks I know exactly where it is breaking.
I will not have to be worried that a bad implementation of Item::getPrice()
is breaking my tests.
How Phake::when() Works¶
Internally Phake is doing quite a bit when this test runs. The three calls to Phake::mock()
are
creating three new classes that in this case each implement the Item
interface. These new classes
each define implementations of any method defined in the Item
interface. If Item
extended another interface, implementations of all of that parent’s defined methods would be created as well. Each
method being implemented in these new classes does a few different things. The first thing that it does is record
the fact that the method was called and stores the parameters that were used to call it. The next significant thing
it does is looks at the stub map for that mock object. The stub map is a map that associates answers to method matchers.
An answer is what a mocked object will return when it is called. By default, a call to a mock object returns a static
answer of NULL. We will discuss answers more in Answers. A method matcher has two parts. The
first is the method name. The second is an array of arguments. The array of arguments will then contain various constraints
that are applied to each argument to see if a given argument will match. The most common constraint is an equality constraint
that will match loosely along the same lines as the double equals sign in PHP. We will talk about matchers more in
Method Parameter Matchers.
When each mock object is initially created, its stub map will be empty. This means that any call to a method on a mock object
is going to return a default answer of NULL. If you want your mock object’s methods to return something else you must add answers
to the stub map. The Phake::when()
method allows you to map an answer to a method matcher for a given mock object.
The mock object you want to add the mapping to is passed as the first parameter to Phake::when()
. The
Phake::when()
method will then return a proxy that can be used add answers to your mock object’s stub
map. The answers are added by making method calls on the proxy just as you would on the mock object you are proxying. In
the first example above you saw a call to Phake::when($this->item1)->getPrice()
.
The getPrice()
call here was telling Phake that I am about to define a new answer that will be returned
any time $this->item->getPrice()
is called in my code. The call to $this->item->getPrice()
returns another object that you can set the answer on using Phake’s fluent api. In the example I called
Phake::when($this->item1)->getPrice()->thenReturn(100)
. The thenReturn()
method will
bind a static answer to a matcher for getPrice()
in the stub map for $this->item1.
Why do Phake stubs return Null by default?¶
The reasoning behind this is that generally speaking, each method you test should depend on only what it needs to perform the (hopefully one) responsibility assigned to it. Normally you will have very controlled delegation to other objects. To help with localization of errors in your test it is assumed that you will always want to mock external dependencies to keep them from influencing the results of unit tests dedicated to the behavior of other parts of the system. Another reason for this default behavior is that it provides consistent and predictable behavior regardless of whether you are testing concrete classes, abstract classes, or interfaces. It should be noted that this default behavior for concrete methods in classes is different then the default behavior in PHPUnit. In PHPUnit, you have to explicitly indicate that you are mocking a method, otherwise it will call the actual method code. There are certainly cases where this is useful and this behavior can be achieved in Phake. I will discuss this aspect of Phake in Partial Mocks.
Overwriting Existing Stubs¶
My shopping cart application is coming right along. I can add items and the total price seems to be accurate. However, while I was playing around with my new cart I noticed a very strange problem. I was playing around with the idea of allowing discounts to be applied to a cart as just additional items that would have a negative price. So while I am playing around with this idea I notice that the math isn’t always adding up. If I start with an item that is $100 and then add a discount that is $81.40 I see that the total price isn’t adding up to $18.60. This is definitely problematic After doing some further research, I realize I made a silly mistake. I am just using simple floats to calculate the costs. Floats are by nature inaccurate. Once you start using them in mathematical operations they start to show their inadequacy for precision. In keeping with the test driven method of creating code I need to create a unit test that shows this flaw.
class ShoppingCartTest extends PHPUnit_Framework_TestCase
{
private $shoppingCart;
private $item1;
private $item2;
private $item3;
public function setUp()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
Phake::when($this->item1)->getPrice()->thenReturn(100);
Phake::when($this->item2)->getPrice()->thenReturn(200);
Phake::when($this->item3)->getPrice()->thenReturn(300);
$this->shoppingCart = new ShoppingCart();
$this->shoppingCart->addItem($this->item1);
$this->shoppingCart->addItem($this->item2);
$this->shoppingCart->addItem($this->item3);
}
public function testGetSub()
{
$this->assertEquals(600, $this->shoppingCart->getSubTotal());
}
public function testGetSubTotalWithPrecision()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
Phake::when($this->item1)->getPrice()->thenReturn(100);
Phake::when($this->item2)->getPrice()->thenReturn(-81.4);
Phake::when($this->item3)->getPrice()->thenReturn(20);
$this->shoppingCart = new ShoppingCart();
$this->shoppingCart->addItem($this->item1);
$this->shoppingCart->addItem($this->item2);
$this->shoppingCart->addItem($this->item3);
$this->assertEquals(38.6, $this->shoppingCart->getSubTotal());
}
}
You can see that I added another test method that uses actual floats for some of the prices as opposed to round numbers. Now when I run my test suite I can see the fantastic floating point issue.
$ phpunit ExampleTests/ShoppingCartTest.php
PHPUnit 3.5.13 by Sebastian Bergmann.
.F
Time: 0 seconds, Memory: 10.25Mb
There was 1 failure:
1) ShoppingCartTest::testGetSubTotalWithPrecision
Failed asserting that <double:38.6> matches expected <double:38.6>.
/home/mikel/Documents/Projects/Phake/tests/ShoppingCartTest.php:95
FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
Generating code coverage report, this may take a moment.
Once you get over the strangeness of 38.6 not equaling 38.6 I want to discuss streamlining test cases with you. You
will notice that the code in ShoppingCartTest::testGetSubTotalWithPrecision()
contains almost
all duplicate code when compared to ShoppingCartTest::setUp()
. If I were to continue following
this pattern of doing things I would eventually have tests that are difficult to maintain. Phake allows you to very
easily override stubs. This is very important in helping you to reduce duplication in your tests and leads to tests
that will be easier to maintain. To overwrite a previous stub you simply have to redefine it. I am going to change
ShoppingCartTest::testGetSubTotalWithPrecision()
to instead just redefine the getPrice()
stubs.
class ShoppingCartTest extends PHPUnit_Framework_TestCase
{
private $shoppingCart;
private $item1;
private $item2;
private $item3;
public function setUp()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
Phake::when($this->item1)->getPrice()->thenReturn(100);
Phake::when($this->item2)->getPrice()->thenReturn(200);
Phake::when($this->item3)->getPrice()->thenReturn(300);
$this->shoppingCart = new ShoppingCart();
$this->shoppingCart->addItem($this->item1);
$this->shoppingCart->addItem($this->item2);
$this->shoppingCart->addItem($this->item3);
}
public function testGetSub()
{
$this->assertEquals(600, $this->shoppingCart->getSubTotal());
}
public function testGetSubTotalWithPrecision()
{
Phake::when($this->item1)->getPrice()->thenReturn(100);
Phake::when($this->item2)->getPrice()->thenReturn(-81.4);
Phake::when($this->item3)->getPrice()->thenReturn(20);
$this->assertEquals(38.6, $this->shoppingCart->getSubTotal());
}
}
If you rerun this test you will get the same results shown in before.
The test itself is much simpler though there is much less unnecessary duplication. The reason this works is because
the stub map I was referring to in How Phake::when() Works isn’t really a map at all. It is more of
a stack in reality. When a new matcher and answer pair is added to a mock object, it is added to the top of the stack.
Then whenever a stub method is called, the stack is checked from the top down to find the first matcher that matches
the method that was called. So, when I created the additional stubs for the various Item::getPrice()
calls, I was just adding additional matchers to the top of the stack that would always get matched first by virtue
of the parameters all being the same.
Resetting A Mock’s Stubs¶
If overriding a stub does not work for your particular case and you would rather start over with all default stubs then
you can use Phake::reset()
and Phake::staticReset()
. These will remove all stubs from a mock and also empty
out all recorded calls against a mock. Phake::reset()
will do this for instance methods on the mock and
Phake::staticReset()
will do this for all static methods on the mock.
Stubbing Multiple Calls¶
Another benefit of the stub mapping in Phake is that it allows you to very easily stub multiple calls to the same
method that use different parameters. In my shopping cart I have decided to add some functionality that will allow
me to easily add multiple products that are a part of a group to the shopping cart. To facilitate this I have decided
to create a new class called ItemGroup
. The ItemGroup
object will be
constructed with an array of Items
. It will have a method on the class that will add all of
the items in the group to the given cart and then the total price of items in the cart will be returned.
It should be noted that earlier I decided to make a small change to the ShoppingCart::addItem()
method to have it return the total price of items in the cart. I figured that this would be nice api level functionality
to make working with the system a little bit easier. I would like to take advantage of that change with this code.
Here’s a stub of the functionality I am considering.
/**
* A group of items that can be added to a cart all at the same time
*/
class ItemGroup
{
/**
* @param array $items an array of Item objects
*/
public function __construct(array $items)
{
}
/**
* @param ShoppingCart $cart
* @return money The new total value of the cart
*/
public function addItemsToCart(ShoppingCart $cart)
{
}
}
The next test I am going to write now is going to be focusing on this new ItemGroup::addItemsToCart()
method. In my test’s setUp()
method I’ll create a new instance of ItemGroup
which will require one or more Item
implementations. I’ll use mocks for those. Then the actual
test case I am going to start with will be a test to assert that ItemGroup::addItemsToCart()
returns the new shopping cart value. I already know that I am going to need to get this value by looking at the
last return value from calls to ShoppingCart::addItem()
. To allow for checking this I will mock
ShoppingCart
and create three stubs for ShoppingCart::addItem()
. Each
stub will be for a call with a different Item
.
class ItemGroupTest extends PHPUnit_Framework_TestCase
{
private $itemGroup;
private $item1;
private $item2;
private $item3;
public function setUp()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
$this->itemGroup = new ItemGroup(array($this->item1, $this->item2, $this->item3));
}
public function testAddItemsToCart()
{
$cart = Phake::mock('ShoppingCart');
Phake::when($cart)->addItem($this->item1)->thenReturn(10);
Phake::when($cart)->addItem($this->item2)->thenReturn(20);
Phake::when($cart)->addItem($this->item3)->thenReturn(30);
$totalCost = $this->itemGroup->addItemsToCart($cart);
$this->assertEquals(30, $totalCost);
}
}
In this example the ShoppingCart::addItem()
method is being stubbed three times. Each time it
is being stubbed with a different parameter being passed to addItem()
. This a good example of
how parameters are also checked whenever Phake looks at a mock object’s stub map for answers. The default behavior
of argument matching is again a loose equality check. Similar to how you would use the double equals operator in PHP.
The other options for argument matching are discussed further in Method Parameter Matchers.
Stubbing Consecutive Calls¶
The previous test was a great example for how you can make multiple stubs for a single method however in reality it
is not the best way for that particular test to be written. What if the Item
objects in an
ItemGroup
aren’t stored in the order they were passed in? I am needlessly binding my test
to the order in which objects are stored. Phake provides the ability to map multiple answers to the same stub. This is
done simply by chaining the answers together. I could rewrite the test from the previous chapter to utilize this
feature of Phake.
class ItemGroupTest extends PHPUnit_Framework_TestCase
{
private $itemGroup;
private $item1;
private $item2;
private $item3;
public function setUp()
{
$this->item1 = Phake::mock('Item');
$this->item2 = Phake::mock('Item');
$this->item3 = Phake::mock('Item');
$this->itemGroup = new ItemGroup(array($this->item1, $this->item2, $this->item3));
}
public function testAddItemsToCart()
{
$cart = Phake::mock('ShoppingCart');
Phake::when($cart)->addItem(Phake::anyParameters())->thenReturn(10)
->thenReturn(20)
->thenReturn(30);
$totalCost = $this->itemGroup->addItemsToCart($cart);
$this->assertEquals(30, $totalCost);
}
}
You will notice a few of differences between this example and the example in Stubbing Multiple Calls. The first
difference is that there is only one call to Phake::when()
. The second difference is that I have chained together three
calls to thenReturn()
. The third difference is instead of passing one of my mock Item
objects I have passed the result of the Phake::anyParameters()
method. This is a special argument
matcher in Phake that essentially says match any call to the method regardless of the number of parameters or the
value of those parameters. You can learn more about Phake::anyParameters()
in wildcard-parameters.
So, this single call to Phake::when()
is saying: “Whenever a call to $cart->addItem()
is made, regardless of the parameters, return 10 for the first call, 20 for the second call, and 30 for the third
call.” If you are using consecutive call stubbing and you call the method more times than you have answers set, the
last answer will continue to be returned. In this example, if $cart->addItem()
were called a fourth
time, then 30 would be returned again.
Stubbing Reference Parameters¶
Occasionally you may run into code that utilizes reference parameters to provide additional output
from a method. This is not an uncommon thing to run into with legacy code. Phake provides a custom
parameter matcher (these are discussed further in Method Parameter Matchers)
that allows you to set reference parameters. It can be accessed using Phake::setReference()
.
The only parameter to this matcher is the value you would like to set the reference parameter
to provided all other parameters match.
interface IValidator
{
/**
* @parm array $data Data to validate
* @parm array &$errors contains all validation errors if the data is not valid
* @return boolean True when the data is valid
*/
public function validate(array $data, array &$errors);
}
class ValidationLogger implements IValidator
{
private $validator;
private $log;
public function __construct(IValidator $validator, Logger $log)
{
$this->validator = $validator;
$this->log = $log;
}
public function validate(array $data, array &$errors)
{
if (!$this->validator->validate($data, $errors))
{
foreach ($errors as $error)
{
$this->log->info("Validation Error: {$error}");
}
return FALSE;
}
return TRUE;
}
}
class ValidationLoggerTest extends PHPUnit_Framework_TestCase
{
public function testValidate()
{
//Mock the dependencies
$validator = Phake::mock('IValidator');
$log = Phake::mock('Logger');
$data = array('data1' => 'value');
$expectedErrors = array('data1 is not valid');
//Setup the stubs (Notice the Phake::setReference()
Phake::when($validator)->validate($data, Phake::setReference($expectedErrors))->thenReturn(FALSE);
//Instantiate the SUT
$validationLogger = new ValidationLogger($validator, $log);
//verify the validation is false and the message is logged
$errors = array();
$this->assertFalse($validationLogger->validate($data, $errors));
Phake::verify($log)->info('Validation Error: data1 is not valid');
}
}
In the example above, I am testing a new class I have created called ValidationLogger
.
It is a decorator for other implementations of IValidator
that allows adding
logging to any other validator. The IValidator::validate()
method will always
return an array of errors into the second parameter (a reference parameter) provided to the method.
These errors are what my logger is responsible for logging. So in order for my test to work properly,
I will need to be able to set that second parameter as a part of my stubbing call.
In the call to Phake::when($validator)->validate()
I have passed a call to
Phake::setReference()
as the second parameter. This is causing the mock
implementation of IValidator
to set $errors
in
ValidationLogger::validate()
to the array specified by $expectedErrors
.
This allows me to quickly and easily validate that I am actually logging the errors returned back
in the reference parameter.
By default Phake::setReference()
will always return true regardless of the
parameter initially passed in. If you would like to only set a reference parameter when that reference
parameter was passed in as a certain value you can use the when()
modifier.
This takes a single parameter matcher as an argument. Below,
you will see that the test has been modified to call when()
on the result
of Phake::setReference()`. This modification will cause the reference parameter
to be set only if the $errors parameter passed to IValidator::validate()
is initially passed as an empty array.
class ValidationLoggerTest extends PHPUnit_Framework_TestCase
{
public function testValidate()
{
//Mock the dependencies
$validator = Phake::mock('IValidator');
$log = Phake::mock('Logger');
$data = array('data1' => 'value');
$expectedErrors = array('data1 is not valid');
//Setup the stubs (Notice the Phake::setReference()
Phake::when($validator)->validate($data, Phake::setReference($expectedErrors)->when(array())->thenReturn(FALSE);
//Instantiate the SUT
$validationLogger = new ValidationLogger($validator, $log);
//verify the validation is false and the message is logged
$errors = array();
$this->assertFalse($validationLogger->validate($data, $errors));
Phake::verify($log)->info('Validation Error: data1 is not valid');
}
}
Please note, when you are using Phake::setReference()
you still must provide
an answer for the stub. If you use this function and your reference parameter is never changed,
that is generally the most common reason.
Partial Mocks¶
When testing legacy code, if you find that the majority of the methods in the mock are using the thenCallParent()
answer, you may find it easier to just use a partial mock in Phake. Phake partial mocks also allow you to call the
actual constructor of the class being mocked. They are created using Phake::partialMock()
. Like Phake::mock()
,
the first parameter is the name of the class that you are mocking. However, you can pass additional parameters that
will then be passed as the respective parameters to that class’ constructor. The other notable feature of a partial
mock in Phake is that its default answer is to pass the call through to the parent as if you were using
thenCallParent()
.
Consider the following class that has a method that simply returns the value passed into the constructor.
class MyClass
{
private $value;
public __construct($value)
{
$this->value = $value;
}
public function foo()
{
return $this->value;
}
}
Using Phake::partialMock()
you can instantiate a mock object that will allow this object to function
as designed while still allowing verification as well as selective stubbing of certain calls.
Below is an example that shows the usage of Phake::partialMock()
.
class MyClassTest extends PHPUnit_Framework_TestCase
{
public function testCallingParent()
{
$mock = Phake::partialMock('MyClass', 42);
$this->assertEquals(42, $mock->foo());
}
}
Again, partial mocks should not be used when you are testing new code. If you find yourself using them be sure to inspect your design to make sure that the class you are creating a partial mock for is not doing too much.
Setting Default Stubs¶
You can also change the default stubbing for mocks created with Phake::mock()
. This is done by using the second
parameter to Phake::mock()
in conjunction with the Phake::ifUnstubbed()
method. The second parameter to
Phake::mock()
is reserved for configuring the behavior of an individual mock. Phake::ifUnstubbed()
allows you
to specify any of the matchers mentioned above as the default answer if any method invocation is not explicitly
stubbed. If this configuration directive is not provided then the method will return NULL by default. An example of
this can be seen below.
class MyClassTest extends PHPUnit_Framework_TestCase
{
public function testDefaultStubs()
{
$mock = Phake::mock('MyClass', Phake::ifUnstubbed()->thenReturn(42));
$this->assertEquals(42, $mock->foo());
}
}
Stubbing Magic Methods¶
Most magic methods can be stubbed using the method name just like you would any other method. The one exception to this
is the __call()
method. This method is overwritten on each mock already to allow for the fluent api that Phake
utilizes. If you want to stub a particular invocation of __call()
you can create a stub for the method you are
targetting in the first parameter to __call()
.
Consider the following class.
class MagicClass
{
public function __call($method, $args)
{
return '__call';
}
}
You could stub an invocation of the __call()
method through a userspace call to magicCall()
with the following code.
class MagicClassTest extends PHPUnit_Framework_TestCase
{
public function testMagicCall()
{
$mock = Phake::mock('MagicClass');
Phake::when($mock)->magicCall()->thenReturn(42);
$this->assertEquals(42, $mock->magicCall());
}
}
If for any reason you need to explicitly stub calls to __call()
then you can use Phake::whenCallMethodWith()
.
The matchers passed to Phake::whenCallMethod()
will be matched to the method name and array of arguments similar to
what you would expect to be passed to a __call()
method. You can also use Phake::anyParameters() instead.
class MagicClassTest extends PHPUnit_Framework_TestCase
{
public function testMagicCall()
{
$mock = Phake::mock('MagicClass');
Phake::whenCallMethodWith('magicCall', array())->isCalledOn($mock)->thenReturn(42);
$this->assertEquals(42, $mock->magicCall());
}
}