Just Mock It Mocks and Stubs
Presented by Gavin Pickin Slides: http://gpickin.com/itb2014/ Website: http://gpickin.com Twitter: @gpickin
Introduc)on
• Follow along with resources from h6p://gpickin.com/itb2014/
• If you want to find out more about me, my website has more than enough informa)on
20 Second Agenda
• Unit Tes)ng -‐ Recap • What is Mocking • What is a Mock / Stub • Why Mock • Let’s look at some Mocking
Unit Tes)ng
“unit tes)ng is a soOware verifica)on and valida)on method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an applica)on” -‐ wikipedia
Unit Tes)ng
• Can improve code quality -‐> quick error discovery
• Code confidence via immediate verifica)on • Can expose high coupling • Will encourage refactoring to produce > testable code
• Remember: Tes)ng is all about behavior and expecta)ons
Bugs Hurt
Bugs Hurt
• Bugs hurt – the later in the process, the harder to fix.
• Test Early and OOen – Find them before they rot your founda)on
• Testable Code is Maintainable Code
Unit Tes)ng Basics
Test Driven Development
Important Tests
• Unit Tes)ng – Test behavior of individual objects
• Integra)on Tes)ng – Test En)re Applica)on from Top Down
• UI verifica)on tes)ng – Verifica)on via HTML/Visual elements
Important Tes)ng Tools
• TestBox (Run BDD and MXUnit style) • IDE -‐ CF Builder / Eclipse • Mocking Framework • ANT • Jenkins, Bamboo, Teamcity, other Cis • Selenium • Jmeter or Webstress Tool, Apache AB
What is Mocking?
According to Merriam Webster • to laugh at or make fun of (someone or something) especially by copying an ac)on or a way of behaving or speaking
• to imitate (as a mannerism) closely
What is Mocking?
"A mock object is an object that takes the place of a ‘real’ object in such a way that makes tes)ng easier and more meaningful, or in some cases, possible at all" by Sco6 Bain -‐ Emergent Design
Mocks
Mocks
Mocks
Mocks
Stub Object
• A stub is an empty container, that represents an Object.
• This can be useful for represen)ng CFCs and Objects that haven’t been wri6en yet.
Why use Mocking
• Isolate your SUT -‐> SoOware Under Test • To build against interfaces & contracts • Building against missing integra)on pieces • To control data and expecta)ons • Mock components whose behavior is undesirable or hard to control
Why Mock?
• How do you test when helper components that are not built yet?
• How do you do controlled excep)ons? • How do you test & control external API calls? • How do you control results from ColdFusion tags or func)ons?
• How do you control network connec)ons? Do you pull the network plug?
Why Mock?
How do you test code like this? <cfdirectory ac)on=”list” directory=”#arguments.path#” name=”qResults”> <ck6p url=”#arguments.urlPath#” results=”qResults”> <cfmail to=”#to#” from=”#from#” subject=”#subject#”>#content#</cfmail> <cfquery /> func)on init(){ var helper = new Helper(); } private func)on getData(){ return data; }
The COLD hard truth – It can Hurt
• Tes)ng some code is hard, or almost impossible.
• Refactor it • Mock it • Test It • With CI, you can forget about it
Un)l it breaks
Refactor to make it Mockable
• Original: <cfdirectory ac)on=”list” directory=”/myapp/path” name=”qResults”>
• Refactored <cffunc)on name=”getFiles” output=”false” returnType=”query”> <cfargument name=”path”> <cfset var qResults = “”> <cfdirectory ac)on=”list” directory=”#arguments.path#” name=”qResults”> ... Process Here ... <cfreturn qResults> </cffunc)on>
Normal View of your Service
Mock/Test View of your Service
What do we Mock?
• Excep)ons • Data • CFC and Objects • Methods in our CFCs • Proper)es in our CFCs
Mocking Framework
• Introducing
What can MockBox do?
• Mock Objects with or without implementa)ons • Mock methods & proper)es in any scope • Create Stub Objects -‐> Non-‐existent objects • Mock excep)ons • Mock arguments to results • Logging & Debugging • Verifica)on methods • State Machine Results
Sepng up MockBox
• Standalone Version (FW/1, Fusebox, Model Glue, Home Brewed) mockBox = createObject(“component”,”mockBox.system.tes)ng.MockBox”).init();
• Running from inside ColdBox (outside of TestBox) mockBox = createObject(“component”,”coldbox.system.tes)ng.MockBox”).init();
Using MockBox
• MockBox does its magic dynamically, adding / decora)ng CFCs with necessary methods.
• CreateMock() user = mockBox.createMock(“model.User”);
• CreateEmptyMock() dao = mockBox.createEmptyMock(“model.UserDAO”);
• PrepareMock() mockBox.prepareMock( service );
Using MockBox -‐ Stubs
• CreateStub() – Create a simple empty Stub – Pass an Implements to get a Mock Interface – Pass an Extends to get a Mock with Inheritance
nonExistentService = mockBox.createStub(); mockInterface = mockBox.createStub(implements=”model.ICache”); mockInheritance = mockbox.createStub(extends=”model.SecurityService”);
Injected Methods
$()
• Argument – method – returns – preserveReturnType – throwExcep)on – throwType – throwDetail – throwMessage – callLogging
// Cascaded mocks mockUser.$(“isFound”,true).$(“isDirty”,true); // Mock Exception mockUser. $(method=”save”, throwsException=true, throwType=”IllegalStateException”, throwMessage=”Invalid User Data”); // Mock Return Objects mockRole = mockBox.createMock(“Role”); service.$(method=”getRole”,returns=mockRole);
Using $()
mockUser = mockBox.createEmptyMock(“model.User”).init(); userService = mockBox.createMock(“model.UserService”).init(); user = userService.$(“get”, mockUser); //Technique 1 – Constant Result user.$(“getName”, “Rose Tyler”); //Technique 2 – Rota)ng Results user.$(“getName”).$results(“Rose Tyler”, “Amelia Pond”, “River Song”);
Using $args()
• Results based on the Arguments Passed • Must be chained via Results. // Call to Mock if( dao.getSepng(“userAudit”) ){ startAudit( dao.getSepng(“auditTables”) ); }; // Mocking Calls dao.$(“getSepng”).$args(“userAudit”).$results(true); dao.$(“getSepng”).$args(“auditTables”).$results(“user,order,
Using $args()
• Arguments are smart like normal func)ons – Posi)onal Arguments
saveUser(”Rose”,”Tyler”);
– Named Arguments saveUser(fname=”Rose”,lname=”Tyler”);
– Argument Collec)ons data = { fname = “Rose”, lname = “Tyler” };
saveUser(argumentCollec)on=data);
$results()
• Your results can be – Constant – Or Sequenced
• Your results will loop over and over.
• Argument Based Results can also be repe))ve in a sequence.
$property()
• Mock any property on any scope • Great for sepngs and dependency injec)on mocking // Mock a sepng on the variables scope service.$property(“cacheAc)ve”,”variables”,true); // Mock a file u)lity object mockU)l = mockbox.createEmptyMock(“u)l.FileU)ls”); service.$property(“fileU)l”,”variables”, mockU)l); // Mock in the variables.instance scope path service.$property(“isDirty”,”instance”,true);
Verifica)on Methods * Verification methods return boolean so they can be asserted
Verifica)on Methods func)on testVerifyCallCount(){
test.$("displayData",queryNew('')); assertTrue( test.$never() ); assertTrue( test.$never(“displayData”) ); test.displayData(); assertFalse( test.$)mes(1,”displayData”) ); assertFalse( test.$once(”displayData”) ); test.displayData(); assertEquals(true, test.$verifyCallCount(2));
}
Verifica)on Methods func)on testMockMethodCallCount(){
test.$("displayData",queryNew('')); test.$("getLuis",1); assertEquals(0, test.$count("displayData") ); assertEquals(-‐1, test.$count("displayData2") );
}
Lets look at a Demo
h6p://justmockit.local.com Code available at: h6ps://github.com/gpickin/justmockitdemo
The End – Thank you
• Thanks everyone for making it this far • All of the materials will be on my ITB presenta)on Site: h6p://www.gpickin.com/itb2014/
• Hit me up on twi6er @gpickin • Read more on my blog: h6p://gpickin.com • Check out my CFO Session Thursday, 15th 11:30am – 12:30am on Lakes Ballroom C