mocking demystified

Download Mocking Demystified

Post on 10-May-2015

4.532 views

Category:

Technology

3 download

Embed Size (px)

DESCRIPTION

Replacing dependents with doubles is a central part of testing that every developer has to master. This talk goes over the different types of doubles and explains their place in testing, how to implement them in a mainstream mocking framework, and which strategies or doubles to use in different message exchange scenarios between objects. After this talk you will have moved a step forward in your understanding of testing in the context of object oriented programming.

TRANSCRIPT

  • 1.Mocking Demystified by @_md

2. how many of youwrite tests? 3. how manywrite tests before the code? 4. how many of youknow what a mock is? 5. how many of you use mocks? 6. ALL YOU NEED TO KNOW ABOUT TESTING (in 5 minutes) 7. testArrangeAct Assert 8. testinstantiateArrangetested object ActAssert 9. instantiateArrangetested object$parser = new MarkdownParser; 10. testArrangerun the methodAct you want to test Assert 11. run the methodActyou want to test$parser = new MarkdownParser;$html = $parser->toHtml(Hello World); 12. testArrangeAct Assert specify theexpected outcome 13. specify theAssert expected outcome$parser = new MarkdownParser;$html = $parser->toHtml(Hello World);assertTrue(

Hello World

== $html); 14. testArrange instantiate tested objectActrun the methodAssertcheck expected outcome 15. $this->toHtml(Hello World) ->shouldReturn(

Hello World

); 16. $this->toHtml(Hello World) ->shouldReturn(

Hello World

); a test is an executable exampleof a class expected behaviour 17. READY TO MOCK AROUND? 18. why? 19. class ParserSubject{public function notify(Event $event){foreach ($this->subscribers as $subscriber) {$subscriber->onChange($event);}}} HOW DO I KNOW NOTIFY WORKS? 20. class ParserSubjectTest extends TestCase{/** @test */function it_notifies_subscribers(){ // arrange$parser = new ParserSubject;// act// I need an event!!!$parser->notify(/* $event ??? */);// assert// how do I know subscriber::onChange got called?}} HOW DO I KNOW NOTIFY WORKS? 21. class EndOfListListener extends EventListener{public function onNewLine(Event $event){$html = $event->getText();if ($this->document->getNextLine() == "") {$html .= "";}return $html;}}HOW DO I CONTROL EVENT AND DOCUMENT 22. {focus on unitexpensive to instantiatewhy?control on collaborators stateindirect outputsundesirable side effects[Meszaros 2007] 23. a mock is just 1 ofmany test double patterns 24. doubles are replacement of anythingthat is not the tested object 25. { dummy fake doubles stub mock spy[Meszaros 2007] 26. {dummy no behaviourfake control indirect outputdoubles stubmockcheck indirect outputspy[Meszaros 2007] 27. a mockist TDD, London school, approach:only the tested object is real 28. DOUBLES WITHOUT BEHAVIOUR 29. dummyhttp://wicker123.deviantart.com/art/Slappy-The-Dummy-148136425 30. testArrangeAct Assert 31. arrange{instantiate (may require collaborators) 32. class MarkdownParser{private $eventDispatcher;public function __construct(EventDispatcher $dispatcher){$this->eventDispatcher = $dispatcher;}}USE DOUBLES TO BYPASS TYPE HINTING 33. class MarkdownParser{private $eventDispatcher;public function __construct(EventDispatcher $dispatcher){$this->eventDispatcher = $dispatcher;}}USE DOUBLES TO BYPASS TYPE HINTING 34. class MarkdownParserTest extends TestCase{function setUp(){$dispatcher = $this->getMock(EventDispatcher);$this->parser = new MardownParser($dispatcher);}} XUNIT EXAMPLE 35. class MarkdownParser extends ObjectBehavior{function let($dispatcher){$dispatcher->beAMockOf(EventDispatcher);$this->beConstructedWith($dispatcher);}}PHPSPEC EXAMPLE 36. http://wicker123.deviantart.com/art/Slappy-The-Dummy-148136425Dummy is a placeholder passed to the SUT (tested object), but never used[Meszaros 2007] 37. dummy: double with no behaviourhttp://wicker123.deviantart.com/art/Slappy-The-Dummy-148136425 38. DOUBLES TO CONTROL INDIRECT OUPUT 39. arrange{instantiate (may require collaborators)further change state 40. class MarkdownParserTest extends TestCase{function setUp(){$dispatcher = $this->getMock(EventDispatcher);$this->parser = new MardownParser($dispatcher);$this->parser->setEncoding(UTF-8);}} FURTHER CHANGE TO THE STATE IN ARRANGE 41. class MarkdownParserTest extends TestCase{function setUp(){$dispatcher = $this->getMock(EventDispatcher);$this->parser = new MardownParser($dispatcher);$this->parser->setEncoding(UTF-8);}} FURTHER CHANGE TO THE STATE IN ARRANGE 42. arrange{instantiate (may require collaborators)further change stateconfigure indirect output 43. class EndOfListListener extends EventListener{public function onNewLine(Event $event){$html = $event->getText();if ($this->document->getNextLine() == "") {$html .= "";}return $html;}}INDIRECT OUTPUTS 44. class EndOfListListener extends EventListener{public function onNewLine(Event $event){$html = $event->getText();if ($this->document->getNextLine() == "") {$html .= "";}return $html;}}INDIRECT OUTPUTS 45. fakestubdoubles for controlling indirect output http://www.ickr.com/photos/fcharlton/1841638596/ http://www.ickr.com/photos/64749744@N00/476724045 46. $event->getText(); // will return Hello World$this->document->getNextLine(); // will return STUBBING: CONTROLLING DOUBLES INDIRECT OUTPUTS 47. function let($event, $document){$event->beAMockOf("Event");$document->beAMockOf("Document");$this->beConstructedWith($document);} IN PHPSPEC 48. function let($event, $document){$event->beAMockOf("Event");$document->beAMockOf("Document");$this->beConstructedWith($document);}function it_ends_list_when_next_is_empty($event, $document){$event->getText()->willReturn("Some text");$document->getNextLine()->willReturn("");} IN PHPSPEC 49. function let($event, $document){$event->beAMockOf("Event");$document->beAMockOf("Document");$this->beConstructedWith($document);}function it_ends_list_when_next_is_empty($event, $document){$event->getText()->willReturn("Some text");$document->getNextLine()->willReturn("");$this->onNewLine($event) ->shouldReturn("Some text");} IN PHPSPEC 50. class EndOfListListener extends EventListener{public function onNewLine(Event $event){$html = $event->getText();if ($this->document->getNextLine() == "") {$html .= "";}return $html;}}THE CODE AGAIN 51. function let($event, $document){$event->beAMockOf("Event");$document->beAMockOf("Document");$this->beConstructedWith($document);}function it_ends_list_when_next_is_empty($event, $document){$event->getText()->willReturn("Some text");$document->getNextLine()->willReturn("");$this->onNewLine($event) ->shouldReturn("Some text");}THE SPEC AGAIN 52. double behaviourloose demand returns null to any method callfake returns null to defined set methodsstub returns value defined or raise error 53. DOUBLES TO SPEC MESSAGE EXCHANGE 54. we said beforea test is an executable example of a class expected behaviour 55. what is behaviour? 56. B = I + O behaviour = input + output 57. what can happen in a method? 58. {return a valuemodify statemethods print somethingthrow an exceptiondelegate 59. {return a valuenot the finalmodify statebehaviourmethods print somethingthrow an exceptiondelegate 60. {methodsreturn a value we should probablyprint something delegate that toothrow an exceptiondelegate 61. {methodsreturn a valuethrow an exceptiondelegate 62. methodstrategyreturns a valuethrows an exceptiondelegates 63. method strategyreturns a value assertions/throws an exceptionexpectationsdelegates mocks & spies 64. Viewpoints Research Institute Source - Bonnie Macbird URL -http://www.vpri.orgThe key in making great and growable systems is much more to design how its modules communicaterather than what their internal propertiesand behaviours should be.Messaging 65. messaging 66. yeah, but what does it mean? 67. $this->person->getCar()->getEngine()->ignite(); 68. Inappropriate Intimacy 69. $this->person->startCar(); 70. tell, dont ask![Sharp 1997] 71. exposing lower level implementation makes the code rigid 72. $this->person->getCar()->getEngine()->ignite(); 73. focus on messagingmakes the code flexible 74. $this->person->startCar(); 75. mockspydoubles for messaging http://www.ickr.com/photos/scribe215/3234974208/ http://www.ickr.com/photos/21560098@N06/5772919201/ 76. class ParserSubject{public function notify(Event $event){foreach ($this->subscribers as $subscriber) {$subscriber->onChange($event);}}} HOW DO I KNOW NOTIFY WORKS? 77. class ParserSubject{public function notify(Event $event){foreach ($this->subscribers as $subscriber) {$subscriber->onChange($event);}}} HOW DO I KNOW NOTIFY WORKS? 78. use mocks to describe how yourmethod will impact collaborators 79. use PHPUnit_Framework_TestCase as TestCase;class ParserSubjectTest extends TestCase{/** @test */ function it_notifies_subscribers(){$event = $this->getMock("Event");$subscriber = $this->getMock("Subscriber");$subscriber->expects($this->once()) ->method("onChange") ->with($event);$parser = new ParserSubject();$parser->attach($subscriber);$parser->notify($event);}} USING PHPUNIT NATIVE MOCK CONSTRUCT 80. public function testUpdateWithEqualTypes(){$installer = $this->createInstallerMock();$manager = new InstallationManager(vendor);$manager->addInstaller($installer);$initial = $this->createPackageMock();$target= $this->createPackageMock();$operation = new UpdateOperation($initial, $target, test);$initial->expects($this->once())->method(getType)->will($this->returnValue(library));$target->expects($this->once())->method(getType)->will($this->returnValue(library));$installer->expects($this->once())->method(supports)->with(library)->will($this->returnValue(true));$installer->expects($this->once())->method(update)->with($this->repository, $initial, $target); EXCESSIVE SETUP 81. github.com/padraicb/mockery 82. use PHPUnit_Framework_TestCase as TestCase;class ParserSubjectTest extends TestCase{/** @test */ function it_notifies_subscribers(){$event = Mockery::mock("Event");$subscriber = Mockery::mock("Subscriber");$subscriber->shouldReceive("onChange") ->with($event);$parser = new ParserSubject();$parser->attach($subscriber);$parser->notify($event);}} USING MOCKERY 83. class ParserSubject extends PHP