stub you!
DESCRIPTION
Phake mocking object presentation to PUG RomeTRANSCRIPT
When you’re doing testingyou’re focusing on one element at a time
Unit testing
mercoledì 26 giugno 13
provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test
Stub objects
mercoledì 26 giugno 13
objects pre-programmed with expectationswhich form a specification of the calls
they are expected to receive
Mock objects
mercoledì 26 giugno 13
A simple stub example
public interface MailService {
public function send(Message $msg);
}
public class MailServiceStub implements MailService {
private $sent = 0;
public function send(Message $msg) {
/*I’m just sent the message */
++$sent;
}
public function numberSent() {
return $this->sent;
}
}
implementation
mercoledì 26 giugno 13
A simple stub example
state verification
class OrderStateTester{...
public function testOrderSendsMailIfFilled() {
$order = new Order(TALISKER, 51);
$mailer = new MailServiceStub();
$order->setMailer($mailer);
$order->fill(/*somestuff*/);
$this->assertEquals(1, $mailer->numberSent());
}
}
mercoledì 26 giugno 13
We’ve wrote a simple test.We’ve tested only one message has been sent
BUT
We’ve not tested it was sent to the right person with right content etc.
mercoledì 26 giugno 13
...using mock object
class OrderInteractionTester...
public function testOrderSendsMailIfFilled() {
$order = new Order(TALISKER, 51);
$warehouse = $this->mock(“Warehouse”);
$mailer = $this->mock(“MailService”);
$order->setMailer($mailer);
$mailer->expects(once())->method("send");
$warehouse->expects(once())->method("hasInventory")
->withAnyArguments()
->will(returnValue(false));
$order->fill($warehouse->proxy());
}
}
mercoledì 26 giugno 13
stub a method
$stub = $this->getMock('Namespace\MyClass');
$stub->expects($this->any())
->method('doSomething')
->with('param')
->will($this->returnValue('returned'));
with PHPUnit
mercoledì 26 giugno 13
stub a method
$stub = $this->getMock('Namespace\MyClass');
$stub->expects($this->any())
->method('doSomething')
->with('param')
->will($this->returnValue('returned'));
$stub = Phake::mock('Namespace\MyClass');
Phake::when($stub)->doSomething('param')->thenReturn('returned');
with PHPUnit
with Phake
mercoledì 26 giugno 13
an exampleclass 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());! }}
mercoledì 26 giugno 13
ShoppingCart implementation
class ShoppingCart
{
! /**
! * 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;
! }
}
mercoledì 26 giugno 13
stubbing multiple calls
$stub = $this->getMock('Namespace\MyClass');
$stub->expects($this->any())
->method('doSomething')
->will($this->returnCallback(function($param) {
$toReturn = array(
'param1' => 'returned1',
'param2' => 'returned2',
}));
with PHPUnit
mercoledì 26 giugno 13
stubbing multiple calls
$stub = $this->getMock('Namespace\MyClass');
$stub->expects($this->any())
->method('doSomething')
->will($this->returnCallback(function($param) {
$toReturn = array(
'param1' => 'returned1',
'param2' => 'returned2',
}));
$stub = Phake::mock('Namespace\MyClass');
Phake::when($stub)->doSomething('param1')->thenReturn('returned1')
Phake::when($stub)->doSomething('param2')->thenReturn('returned2');
with PHPUnit
with Phake
mercoledì 26 giugno 13
an exampleclass 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(60, $totalCost);! }}
mercoledì 26 giugno 13
an example with consecutive callsclass 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);! }}
mercoledì 26 giugno 13
partial mockclass MyClass{! private $value;
! public __construct($value)! {! ! $this->value = $value;! }
! public function foo()! {! ! return $this->value;! }}
mercoledì 26 giugno 13
partial mockclass MyClass{! private $value;
! public __construct($value)! {! ! $this->value = $value;! }
! public function foo()! {! ! return $this->value;! }}
class MyClassTest extends PHPUnit_Framework_TestCase{! public function testCallingParent()! {! ! $mock = Phake::partialMock('MyClass', 42);
! ! $this->assertEquals(42, $mock->foo());! }}
mercoledì 26 giugno 13
default stub
class MyClassTest extends PHPUnit_Framework_TestCase
{
! public function testDefaultStubs()
! {
! ! $mock = Phake::mock('MyClass', Phake::ifUnstubbed()->thenReturn(42));
! ! $this->assertEquals(42, $mock->foo());
! }
}
class MyClass{! private $value;
! public __construct($value)! {! ! $this->value = $value;! }
! public function foo()! {! ! return $this->value;! }}
mercoledì 26 giugno 13
stubbing magic methods
class MagicClass{ public function __call($method, $args)
{return '__call';
}}
mercoledì 26 giugno 13
stubbing magic methods
class MagicClass{ public function __call($method, $args)
{return '__call';
}}
class MagicClassTest extends PHPUnit_Framework_TestCase{ public function testMagicCall() { $mock = Phake::mock('MagicClass');
Phake::when($mock)->myMethod()->thenReturn(42);
$this->assertEquals(42, $mock->myMethod()); }}
MyMethod is handled by __call() method
mercoledì 26 giugno 13
verify invocations
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = $this->getMock('PhakeTest_MockedClass');
$mock->expects($this->once())->method('fooWithArgument')
->with('foo');
$mock->expects($this->once())->method('fooWithArgument')
->with('bar');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
}
}
with PHPUnit - BAD!
mercoledì 26 giugno 13
verify invocations
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = $this->getMock('PhakeTest_MockedClass');
$mock->expects($this->once())->method('fooWithArgument')
->with('foo');
$mock->expects($this->once())->method('fooWithArgument')
->with('bar');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
}
}
with PHPUnit - BAD!
//I’m failing, with you!
mercoledì 26 giugno 13
verify invocations
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = $this->getMock('PhakeTest_MockedClass');
$mock->expects($this->at(0))->method('fooWithArgument')
->with('foo');
$mock->expects($this->at(1))->method('fooWithArgument')
->with('bar');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
}
}
with PHPUnit - BETTER
mercoledì 26 giugno 13
verify invocations
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
Phake::verify($mock)->fooWithArgument('foo');
Phake::verify($mock)->fooWithArgument('bar');
}
}
with Phake
mercoledì 26 giugno 13
verify invocations
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('foo');
Phake::verify($mock, Phake::times(2))->fooWithArgument('foo');
}
}
with Phake - multiple invocation
Phake::times($n)Phake::atLeast($n)Phake::atMost($n)
options:
mercoledì 26 giugno 13
verify invocations in order
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
Phake::inOrder(
Phake::verify($mock)->fooWithArgument('foo'),
Phake::verify($mock)->fooWithArgument('bar')
);
}
}
mercoledì 26 giugno 13
verify no interaction
class MyTest extends PHPUnit_Framework_TestCase{ public function testPHPUnitNoInteraction() { $mock = $this->getMock('PhakeTestCase_MockedClass'); $mock->expects($this->never()) ->method('foo');
//.... }}
with PHPUnit
mercoledì 26 giugno 13
verify no interaction
class MyTest extends PHPUnit_Framework_TestCase{ public function testPHPUnitNoInteraction() { $mock = $this->getMock('PhakeTestCase_MockedClass'); $mock->expects($this->never()) ->method('foo');
//.... }}
with PHPUnit
class MyTest extends PHPUnit_Framework_TestCase{ public function testPhakeNoInteraction() { $mock = Phake::mock('PhakeTestCase_MockedClass'); //... Phake::verifyNoInteractions($mock); }}
with Phake
mercoledì 26 giugno 13
verify magic calls
class MagicClass{ public function __call($method, $args) { return '__call'; }}
mercoledì 26 giugno 13
verify magic calls
class MagicClass{ public function __call($method, $args) { return '__call'; }}
class MagicClassTest extends PHPUnit_Framework_TestCase
{
public function testMagicCall()
{
$mock = Phake::mock('MagicClass');
$mock->myMethod();
Phake::verify($mock)->myMethod();
}
}
mercoledì 26 giugno 13
throwing exception
class MyClass{! private $logger;!! public function __construct(Logger $logger)! {! ! $this->logger = $logger;! }
! public function processSomeData(MyDataProcessor $processor, MyData $data)! {! ! try {! ! ! $processor->process($data);! ! }! ! catch (Exception $e) {! ! ! $this->logger->log($e->getMessage());! ! }! }}
Suppose you have a class that logs a message with the exception message
mercoledì 26 giugno 13
throwing exception
class MyClassTest extends PHPUnit_Framework_TestCase{! public function testProcessSomeDataLogsExceptions()! {! ! $logger = Phake::mock('Logger');! ! $data = Phake::mock('MyData');! ! $processor = Phake::mock('MyDataProcessor');! !
Suppose you have a class that logs a message with the exception message
mercoledì 26 giugno 13
throwing exception
class MyClassTest extends PHPUnit_Framework_TestCase{! public function testProcessSomeDataLogsExceptions()! {! ! $logger = Phake::mock('Logger');! ! $data = Phake::mock('MyData');! ! $processor = Phake::mock('MyDataProcessor');! !
Suppose you have a class that logs a message with the exception message
! ! Phake::when($processor)->process($data) ->thenThrow(new Exception('My error message!');
mercoledì 26 giugno 13
throwing exception
class MyClassTest extends PHPUnit_Framework_TestCase{! public function testProcessSomeDataLogsExceptions()! {! ! $logger = Phake::mock('Logger');! ! $data = Phake::mock('MyData');! ! $processor = Phake::mock('MyDataProcessor');! !
Suppose you have a class that logs a message with the exception message
! ! Phake::when($processor)->process($data) ->thenThrow(new Exception('My error message!');
! ! $sut = new MyClass($logger);! ! $sut->processSomeData($processor, $data);
mercoledì 26 giugno 13
throwing exception
class MyClassTest extends PHPUnit_Framework_TestCase{! public function testProcessSomeDataLogsExceptions()! {! ! $logger = Phake::mock('Logger');! ! $data = Phake::mock('MyData');! ! $processor = Phake::mock('MyDataProcessor');! !
Suppose you have a class that logs a message with the exception message
! ! Phake::when($processor)->process($data) ->thenThrow(new Exception('My error message!');
! ! $sut = new MyClass($logger);! ! $sut->processSomeData($processor, $data);
! ! Phake::verify($logger)->log('My error message!');! }}
mercoledì 26 giugno 13
parameter capturinginterface CardCollection{ public function getNumberOfCards();}
class MyPokerGameTest extends PHPUnit_Framework_TestCase{ public function testDealCards() { $dealer = Phake::partialMock('MyPokerDealer'); $players = Phake::mock('PlayerCollection');
$cardGame = new MyPokerGame($dealer, $players);
Phake::verify($dealer)->deal(Phake::capture($deck), $players);
$this->assertEquals(52, $deck->getNumberOfCards()); }}
Class MyPokerDealer{ public function getNumberOfCards(){ .. .. $dealer->deal($deck, $players) }}
mercoledì 26 giugno 13
Phake
pear channel-discover pear.digitalsandwich.compear install digitalsandwich/Phake
Available via pear
Available via Composer
"phake/phake": "dev-master"
mercoledì 26 giugno 13