Reputation: 909
I'm creating tests for a class that takes in a "Search" class, which searches a supermarket using a search string and has a method "getItem($itemNo)" that returns the corresponding item.
So, a bit like this:
class MyClass
{
public function __construct(Search $search) {
$item0 = $search->getItem(0);
$item1 = $search->getItem(1);
// etc... you get the picture
}
}
I want to mock this Search class, as I don't want to search the supermarket everytime I do a test.
So I've written:
class MyClassTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$searchResults=$this->getMockBuilder('Search')
//Because the constructor takes in a search string:
->disableOriginalConstructor()
->getMock();
$pseudoSupermarketItem=array( "SearchResult1", "SearchResult2", etc...);
$this->searchResult
->expects($this->any())
->method('getItem')
->with(/*WHAT DO I PUT HERE SO THAT THE METHOD WILL TAKE IN A NUMBER*/)
->will($this->returnValue($pseudoSupermarketItem[/* THE NUMBER THAT WAS PUT IN */]));
}
}
As you can see in the code, I would like the mock method to take in an integer, like shown in MyClass, which will then return the corresponding pseudoSupermarketItem string. So far I'm not sure how to make this happen, any help is appreciated!
Upvotes: 5
Views: 12356
Reputation: 70853
PHPUnit offers returnValueMap()
for those cases where the input parameters should trigger a defined return value.
// Create a map of arguments to return values.
$map = array(
array(0, 'SearchResult0'),
array(1, 'SearchResult1')
);
// Configure the stub.
$searchResults->expects($this->any())
->method('getItem')
->will($this->returnValueMap($map));
$this->assertEquals('SearchResult0', $searchResults->getItem(0));
$this->assertEquals('SearchResult1', $searchResults->getItem(1));
$this->assertEquals('SearchResult0', $searchResults->getItem(0));
The map does look a bit strange at first, because there is not direct key->value assignment, but that is because this map also works with more than one input parameter for the mocked method.
$mockedAddition = array(
array(0, 0, 0),
array(0, 1, 1),
array(1, 0, 1),
array(1, 1, 2),
);
$calculator->expects($this->any())
->method('add')
->will($this->returnValueMap($mockedAddition);
$this->assertSame(0, $calculator->add(0, 0)); // Returns the value x of (0, 0, x)
$this->assertSame(1, $calculator->add(1, 0)); // Returns the value x of (1, 0, x)
$this->assertSame(1, $calculator->add(0, 1)); // Returns the value x of (0, 1, x)
Upvotes: 2
Reputation: 11364
This should work for you:
$this->searchResult
->expects($this->any())
->method('getItem')
->with($this->isType('integer'))
->will($this->returnCallback(function($argument) use ($pseudoSupermarketItem) {
return $pseudoSupermarketItem[$argument];
});
In additional maybe you may find it useful (using onConsecutiveCalls
):
http://phpunit.de/manual/3.7/en/test-doubles.html#test-doubles.stubs.examples.StubTest7.php
The thrid way is something like that:
$this->searchResult
->expects($this->at(0))
->method('getItem')
->with($this->equalTo(0))
->will($this->returnValue($pseudoSupermarketItem[0]);
$this->searchResult
->expects($this->at(1))
->method('getItem')
->with($this->equalTo(1))
->will($this->returnValue($pseudoSupermarketItem[1]);
// (...)
Upvotes: 9