Share
Embed
Transcript
43 slides
-
When you’re doing testing you’re focusing on one element at
a time Unit testing mercoledì 26 giugno 13 -
to make a single unit work you often need other
units The problem is 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 expectations which 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'));
$stub = Phake::mock('Namespace\MyClass'); Phake::when($stub)->doSomething('param')->thenReturn('returned'); with PHPUnit with Phake mercoledì 26 giugno 13 -
an example 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()); ! } } 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 example 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(60, $totalCost); ! } } mercoledì 26 giugno 13 -
an example with consecutive calls 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); ! } } mercoledì 26 giugno 13 -
partial mock class MyClass { ! private $value; ! public
__construct($value) ! { ! ! $this->value = $value; ! } ! public function foo() ! { ! ! return $this->value; ! } } mercoledì 26 giugno 13 -
partial mock class 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 capturing interface 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.com pear install digitalsandwich/Phake Available via pear
Available via Composer "phake/phake": "dev-master" mercoledì 26 giugno 13