Reputation: 3350
My scenario is similar to below:
class ToMock
{
public function iReturn()
{
return time();
}
public function callMe1($arg1, $arg2)
{
return true;
}
public function callMe2($arg1, $arg2)
{
return true;
}
}
class ToTest
{
public function feedMe(ToMock $toMock)
{
if ($toMock->iReturn() > 100) {
$toMock->callMe1(5, 10);
}
if ($toMock->iReturn() < 200) {
$toMock->callMe2(15, 20);
}
}
}
Now, I want to test if ToMock::iReturn()
returns 150, ToTest::feedMe()
calls ToMock::callMe1()
once with 5 and 10, and ToMock::callMe2()
once with 15 and 20.
I know I can mock the ToMock::iReturn
to return 150, also I can mock ToMock
to expect a particular method once with supplied argument. But, is it possible to do all of these together in the same time? if yes, how would it look like?
Upvotes: 0
Views: 1681
Reputation: 9582
Yes, it is.
Here's an example of a test that covers ToTest
:
<?php
use PHPUnit\Framework\TestCase;
class ToTestTest extends TestCase
{
/**
* @dataProvider providerTimeBetween0And100
*
* @param int $time
*/
public function testFeedMeWhenTimeIsBetween0And100($time)
{
$toMock = $this->createMock(ToMock::class);
$toMock
->expects($this->exactly(2))
->method('iReturn')
->willReturn($time);
$toMock
->expects($this->never())
->method('callMe1');
$toMock
->expects($this->once())
->method('callMe2')
->with(
$this->identicalTo(15),
$this->identicalTo(20)
);
$toTest = new ToTest();
$toTest->feedMe($toMock);
}
public function providerTimeBetween0And100()
{
return $this->providerTimeBetween(0, 100);
}
/**
* @dataProvider providerTimeBetween101And199
*
* @param int $time
*/
public function testFeedMeWhenTimeIsBetween101And199($time)
{
$toMock = $this->createMock(ToMock::class);
$toMock
->expects($this->exactly(2))
->method('iReturn')
->willReturn($time);
$toMock
->expects($this->once())
->method('callMe1')
->with(
$this->identicalTo(5),
$this->identicalTo(10)
);
$toMock
->expects($this->once())
->method('callMe2')
->with(
$this->identicalTo(15),
$this->identicalTo(20)
);
$toTest = new ToTest();
$toTest->feedMe($toMock);
}
public function providerTimeBetween101And199()
{
return $this->providerTimeBetween(101, 199);
}
/**
* @dataProvider providerTimeGreaterThan199
*
* @param int $time
*/
public function testFeedMeWhenTimeIsGreaterThan199($time)
{
$toMock = $this->createMock(ToMock::class);
$toMock
->expects($this->exactly(2))
->method('iReturn')
->willReturn($time);
$toMock
->expects($this->once())
->method('callMe1')
->with(
$this->identicalTo(5),
$this->identicalTo(10)
);
$toMock
->expects($this->never())
->method('callMe2');
$toTest = new ToTest();
$toTest->feedMe($toMock);
}
public function providerTimeGreaterThan199()
{
return $this->providerTimeBetween(200, 300);
}
private function providerTimeBetween($min, $max)
{
for ($time = $min; $time < $max; ++$time) {
yield [
$time
];
}
}
}
Note how multiple expectations are set up using expects()
and further constraints. All of these can be easily combined.
For reference, see:
Upvotes: 1
Reputation: 1038
If I understood your question correctly then test code could look like
class MockingExpectationsTest extends PHPUnit_Framework_TestCase
{
private $obj;
private $mock;
public function setUp(){
$this->mock = $this->createMock(ToMock::class);
$this->obj = new ToTest();
}
public function testExpectations(){
$this->mock->expects($this->exactly(2))
->method('iReturn')
->willReturn(150);
$this->mock->expects($this->exactly(1))
->method('callMe1')
->with(5, 10);
$this->mock->expects($this->exactly(1))
->method('callMe2')
->with(15, 20);
$this->obj->feedMe($this->mock);
}
}
Upvotes: 1