Stub you!

993 views

Published on

Phake mocking object presentation to PUG Rome

Published in: Technology, Education
  • Be the first to comment

Stub you!

  1. 1. Stub you!Andrea Giuliano@bit_sharkmercoledì 26 giugno 13
  2. 2. When you’re doing testingyou’re focusing on one element at a timeUnit testingmercoledì 26 giugno 13
  3. 3. to make a single unit workyou often need other unitsThe problem ismercoledì 26 giugno 13
  4. 4. provide canned answers to calls made during thetest, usually not responding at all to anythingoutside whats programmed in for the testStub objectsmercoledì 26 giugno 13
  5. 5. objects pre-programmed with expectationswhich form a specification of the callsthey are expected to receiveMock objectsmercoledì 26 giugno 13
  6. 6. Mock objectsBehaviourverificationStateverificationStub objectsmercoledì 26 giugno 13
  7. 7. A simple stub examplepublic 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;}}implementationmercoledì 26 giugno 13
  8. 8. A simple stub examplestate verificationclass 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
  9. 9. We’ve wrote a simple test.We’ve tested only one message has been sentBUTWe’ve not tested it was sent to the rightperson with right content etc.mercoledì 26 giugno 13
  10. 10. ...using mock objectclass 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
  11. 11. PHAKEPHP MOCKING FRAMEWORKmercoledì 26 giugno 13
  12. 12. Zero-configPhake was designed with PHPUnit in mindmercoledì 26 giugno 13
  13. 13. stub a method$stub = $this->getMock(NamespaceMyClass);$stub->expects($this->any())->method(doSomething)->with(param)->will($this->returnValue(returned));with PHPUnitmercoledì 26 giugno 13
  14. 14. stub a method$stub = $this->getMock(NamespaceMyClass);$stub->expects($this->any())->method(doSomething)->with(param)->will($this->returnValue(returned));$stub = Phake::mock(NamespaceMyClass);Phake::when($stub)->doSomething(param)->thenReturn(returned);with PHPUnitwith Phakemercoledì 26 giugno 13
  15. 15. 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
  16. 16. ShoppingCart implementationclass ShoppingCart{! /**! * Returns the current sub total of the customers order! * @return money! */! public function getSubTotal()! {! ! $total = 0;! ! foreach ($this->items as $item)! ! {! ! ! $total += $item->getPrice();! ! }! ! return $total;! }}mercoledì 26 giugno 13
  17. 17. stubbing multiple calls$stub = $this->getMock(NamespaceMyClass);$stub->expects($this->any())->method(doSomething)->will($this->returnCallback(function($param) {$toReturn = array(param1 => returned1,param2 => returned2,}));with PHPUnitmercoledì 26 giugno 13
  18. 18. stubbing multiple calls$stub = $this->getMock(NamespaceMyClass);$stub->expects($this->any())->method(doSomething)->will($this->returnCallback(function($param) {$toReturn = array(param1 => returned1,param2 => returned2,}));$stub = Phake::mock(NamespaceMyClass);Phake::when($stub)->doSomething(param1)->thenReturn(returned1)Phake::when($stub)->doSomething(param2)->thenReturn(returned2);with PHPUnitwith Phakemercoledì 26 giugno 13
  19. 19. 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
  20. 20. 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
  21. 21. partial mockclass MyClass{! private $value;! public __construct($value)! {! ! $this->value = $value;! }! public function foo()! {! ! return $this->value;! }}mercoledì 26 giugno 13
  22. 22. 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
  23. 23. default stubclass 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
  24. 24. stubbing magic methodsclass MagicClass{public function __call($method, $args){return __call;}}mercoledì 26 giugno 13
  25. 25. stubbing magic methodsclass 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() methodmercoledì 26 giugno 13
  26. 26. verify invocationsclass 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
  27. 27. verify invocationsclass 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
  28. 28. verify invocationsclass 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 - BETTERmercoledì 26 giugno 13
  29. 29. verify invocationsclass 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 Phakemercoledì 26 giugno 13
  30. 30. verify invocationsclass 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 invocationPhake::times($n)Phake::atLeast($n)Phake::atMost($n)options:mercoledì 26 giugno 13
  31. 31. verify invocations in orderclass 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
  32. 32. verify no interactionclass MyTest extends PHPUnit_Framework_TestCase{public function testPHPUnitNoInteraction(){$mock = $this->getMock(PhakeTestCase_MockedClass);$mock->expects($this->never())->method(foo);//....}}with PHPUnitmercoledì 26 giugno 13
  33. 33. verify no interactionclass MyTest extends PHPUnit_Framework_TestCase{public function testPHPUnitNoInteraction(){$mock = $this->getMock(PhakeTestCase_MockedClass);$mock->expects($this->never())->method(foo);//....}}with PHPUnitclass MyTest extends PHPUnit_Framework_TestCase{public function testPhakeNoInteraction(){$mock = Phake::mock(PhakeTestCase_MockedClass);//...Phake::verifyNoInteractions($mock);}}with Phakemercoledì 26 giugno 13
  34. 34. verify magic callsclass MagicClass{public function __call($method, $args){return __call;}}mercoledì 26 giugno 13
  35. 35. verify magic callsclass 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
  36. 36. throwing exceptionclass 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 messagemercoledì 26 giugno 13
  37. 37. throwing exceptionclass 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 messagemercoledì 26 giugno 13
  38. 38. throwing exceptionclass 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
  39. 39. throwing exceptionclass 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
  40. 40. throwing exceptionclass 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
  41. 41. 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
  42. 42. Phakepear channel-discover pear.digitalsandwich.compear install digitalsandwich/PhakeAvailable via pearAvailable via Composer"phake/phake": "dev-master"mercoledì 26 giugno 13
  43. 43. Questions?Thanks!Andrea Giuliano@bit_sharkmercoledì 26 giugno 13

×