Logout succeed
Logout succeed. See you again!

The Grumpy Programmer's PHPUnit Cookbook PDF
Preview The Grumpy Programmer's PHPUnit Cookbook
The Grumpy Programmer’s PHPUnit Cookbook Chris Hartjes Thisbookisforsaleathttp://leanpub.com/grumpy-phpunit Thisversionwaspublishedon2013-04-06 ThisisaLeanpubbook.Leanpubempowersauthorsand publisherswiththeLeanPublishingprocess.Lean Publishingistheactofpublishinganin-progressebook usinglightweighttoolsandmanyiterationstogetreader feedback,pivotuntilyouhavetherightbookandbuild tractiononceyoudo. ©2012-2013ChrisHartjes Contents Foreword i Acknowledgements vi Introduction vii PHPUnitForGrumpyDevelopers 1 InstallingAndConfiguring . . . . . . . . . . . . . 1 MinimumViableTestClass . . . . . . . . . . . . . 4 MakingYourTestsTellYouWhat’sFailed . . . . . 5 ConfiguringRunTimeOptions . . . . . . . . . . . 8 TestEnvironmentConfiguration . . . . . . . . . . 10 OrganizingYourTests . . . . . . . . . . . . . . . . 13 TestDoubles 22 WhyWeNeedThem . . . . . . . . . . . . . . . . . 22 WhatAreThey . . . . . . . . . . . . . . . . . . . . 23 DummyObjects . . . . . . . . . . . . . . . . . . . 23 TestStubs . . . . . . . . . . . . . . . . . . . . . . . 25 TestSpies . . . . . . . . . . . . . . . . . . . . . . . 32 MoreObjectTestingTricks . . . . . . . . . . . . . . 34 CONTENTS DataProviders 37 WhyYouShouldUseDataProviders . . . . . . . . 37 LookAtAllThoseTests . . . . . . . . . . . . . . . 38 CreatingDataProviders . . . . . . . . . . . . . . . 39 MoreComplexExamples . . . . . . . . . . . . . . . 41 DataProviderTricks . . . . . . . . . . . . . . . . . 42 CreatingTestData 43 DataSourceSnapshots . . . . . . . . . . . . . . . . 43 FakeItWhenYouNeedTo . . . . . . . . . . . . . . 46 TestingAPI’s 48 TestingTalkingToTheAPIItself . . . . . . . . . . 49 WrappingYourAPICalls . . . . . . . . . . . . . . 50 TestingDatabases 56 FunctionalTestsvs.UnitTests . . . . . . . . . . . . 57 Sandboxes . . . . . . . . . . . . . . . . . . . . . . . 58 DBUnit . . . . . . . . . . . . . . . . . . . . . . . . 60 OurFirstDBUnitTest . . . . . . . . . . . . . . . . 71 MockingDatabaseConnections . . . . . . . . . . . 73 Mockingvs.Fixtures . . . . . . . . . . . . . . . . . 76 CONTENTS TestingExceptions 80 TestingUsingAnnotations . . . . . . . . . . . . . . 81 TestingUsingsetExpectedException . . . . . . . . 82 TestingUsingtry-catch . . . . . . . . . . . . . . . 83 Foreword Justin Searls is what I like to call a “testing brother from another mother”. He works with the awesome folks at Test Double¹ providing consulting services for people doing Ruby andJavascript,withafocusontesting.HeandIhavehadsome interesting discussions about testing in general and I asked himtoprovidehisperspectiveonthebenefitsoftesting. I first used PHP to build a web application in 2004. By that time, I’d already been taught – and had failed to learn the benefits of – unit testing and even test-driven development. Inthiscase,Ijustwantedtogetmyapplicationwritten,with asfewsecondaryconcernstoworryaboutaspossible. Developing in PHP made me happy. Both the language and its community seemed focused squarely on helping me get things done, and they didn’t impose an expectation that I adoptanyhighfalutin’practicesorconventions.Asaresult,I wasiteratingonaworkingapplicationfromdayone. And “day one” was hugely productive! The same went for “week one”. As it happened, “month one” was such a success that I had completed the minimum requirements of an ap- plication for which I’d been given over 20 weeks’ worth of budget. Isoondiscovered,however,thattherewastroubleinparadise. Slowly, adding small features had begun to take me signifi- cantly more time than I’d been accustomed to large features taking. While I’d previously been a beacon of workplace optimism and excitement, I noticed that I was spending a largerproportionofmydayfeelingconfusedandfrustrated.I ¹http://testdouble.com i Foreword ii wasn’tonlydreadingshowingupforwork,I’devenbegunto resentmyeditor’sapplicationicon,becauseclickingitmeant thatIwasinforabadtime. Therootcause,andit’splainlyobvioustoanyonewhomight read my code, is that the source had grown into a tangled jungleofroguemega-functions,repletewithtreesoftowering switch statements and swamps of nested if-else constructs. Thecodelackedanyrhymeorreason.Itcontainednohelpful signposts to my future self. Concerning myself with the design of the code hadn’t seemed necessary, because my intimate,almostinstinctualknowledgeofthecodehadmade mesoproductiveattheproject’soutset. But at some point, the complexity of my application’s code had increased beyond what I could hold in my brain at a single time. Prior to that point, I had been unfettered; liberatedfromformalitieslikeup-frontdesignormaintaining automatedtests.Beyondthatpoint,though,Icouldsensethat myhastehadcorneredmeintoadeadend.Theonlyquestion was: could I re-bottle whatever genie I’d released to help me becomesoproductiveinthefirstplace? Inthecaseofthatapplication,theanswerwas“no”;Icouldn’t makethingsbetter.Thedrasticinternalchangesnecessaryto maketheapplicationeasiertomaintainwouldhaverequired confidence that my changes didn’t break anything. At the time, I lacked the expertise to write the automated tests I wouldhaveneededtogainsaidconfidencetomakeanymajor changes. Ultimately, I relented and stayed on the path of most resistance, muscling my way through to the end of the project. Needless to say, no one was as impressed with my productivity during the final leg of the project as they had beenafteritsglorious“monthone”. Foreword iii At this point, it might seem like I told this cautionary tale for the purpose of exhorting to readers, “see?! That’s why you start writing tests for everything on day one! Because even if you feel great today, someday your application will explodewithcomplexityandyou’llbemiserable”.Iwon’tsay that, however, because that would be a specious, dogmatic argument and it would oversimplify the world of rich and subtlechallengesfacingsoftwaredevelopers.Thereare,after all, many ways to ship working software with acceptable maintainability; excellent software can absolutely be written withoutanyautomatedtestsatall. So if testing isn’t absolutely necessary for success, why is it valuable?Theansweristhatautomatedtestsareanexcellent toolforestablishingtight,rapidfeedbackloopswhencreating andchangingcode.Toexplain,letmerewindtothebeginning ofmystory. I said that working with PHP made me happy, because I felt the extraordinary positive feedback of seeing something, albeit small, start working in the first couple of hours. Not only that, but I could get ongoing feedback that my changes workedasquicklyasIcouldsaveafileandrefreshabrowser window. It was only once my application had grown signifi- cantlythatthefeedbackloophadstartedtoslowdown–afive secondpausehere,afewclickstosetuptheappthere,perhaps afewminutestoverifythechangedidn’tintroduceanybugs. WhatIeventuallyrealizedthatIwantedwasforeverydayto feellike“dayone”ofafreshproject;Iwantedarapidfeedback looptobesustainableforthelifeoftheapplication. In the past, I had tried building applications of a similar scope with other tech stacks, like Java, known for their long- term“hardiness”.Butmyprojectsneverseemedtogetoffthe Foreword iv ground.IfailedinpartbecauseI’dsinkthefirst,crucialhours of my motivation into troubleshooting while setting up the recommendedbuildtoolsandsupportinglibraries.Andeven when I managed to clear that hurdle, any sense of progress wasstymiedbythenaggingdoubtthatmyarchitecturewould elicit the judgment of my contemporaries. Perhaps a more durable technology stack or application design would have made my rapid feedback loop more sustainable in the long run, but the initial “short run” was so painful that I’d never findoutwhatthelongrun”feltlike. It turns out that a “sense of progress” is crucial to produc- tive software development. Feedback, both positive (“that worked!”)andnegative(“thatdoesn’t!”)hasahugeimpacton the psyche of the developer. When people endeavor to build tangiblethings,theyreceiveconcretefeedbackaboutprogress constantly (e.g. “the table has two legs, so I’m about halfway done”; “this book introduction has 283 words, so I’ve got a ways to go”). But when building something as ephemeral as software, progress comes in fits and starts, sometimes to the pointoffeelingillusory. The magic of unit testing, particularly in the context of test- drivendevelopment,isthatitgivesthedevelopertheabilityto controlhisorherownsenseofprogress.Traditionalfeedback requires our fully integrated application and our eyeballs to assert whether we’re on the right track or wrong track. Unit testing allows us to establish a feedback loop at whatever level-of-integration we wish (e.g. perhaps a bunch of objects in coordination, perhaps one function in pure isolation), so long as we can imagine and implement a way to assert working behavior that doesn’t require our eyeballs’ manual inspection.Inthisway,evenifwe’refacedwithimplementing asolutionofdauntingcomplexity,unittestscanusuallyhelp Foreword v us break the problem down in such a way that we can make (and importantly, feel!) incremental progress on our path to overallcompletion. By mastering both the tools and craft of unit testing, rapid feedback is attainable regardless of the age or complexity of the project. At the outset of an application’s life, a failing test can help us set up the critical infrastructure of our application,andwecangetsomemotivatingfeedbackevenif there’snothingvisibletousersyet.Andforamatureproject, however tangled its source, a test can usually be crafted to gaincertaintythatachangewasmadesafelyandsuccessfully. Whenappliedrigorouslyandconsistently,andwhenthepain of a hard-to-write test is responded to with improvement to the design of the code being tested, developers can hope to remainhappyandproductiveoverthelifeofanyapplication. There’s a lot more to learn about how to get there, but that’s what the rest of this book is for! My hope is that the lessons that Chris has prepared in this book will serve to equip you withtheskillstosomedayfindyourselfworkingonamature applicationwhilefeelingasproductiveasyoudidondayone. • JustinSearls