Tdd iPhone For Dummies
Upcoming SlideShare
Loading in...5
×
 

Tdd iPhone For Dummies

on

  • 4,233 views

Everything you must know to start develop iPhone Applications in safe and fun way!

Everything you must know to start develop iPhone Applications in safe and fun way!

Statistics

Views

Total Views
4,233
Views on SlideShare
4,176
Embed Views
57

Actions

Likes
7
Downloads
69
Comments
3

4 Embeds 57

http://www.slideshare.net 30
http://www.whymca.org 25
http://conference2010.whymca.org 1
http://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-ShareAlike LicenseCC Attribution-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • really interesting and useful
    the images used in the presentation are very funny
    thank you!
    Are you sure you want to
    Your message goes here
    Processing…
  • Grazie mille!
    Ho cercato di essere leggero e stuzzicare la curiosità in modo da approfondire un tema molto importante.
    Sono felice che entrambi gli scopi siano stati raggiunti :-)
    Are you sure you want to
    Your message goes here
    Processing…
  • Ottima presentazione. Complimenti anche per l'esposizione fluida e per niente noisa.
    Lo speech ha sicuramente stuzzicato la mia attenzione con spunti di riflessione davvero interessanti, c'è molto da crescere nell'ambito TDD per Objective-c e a maggior ragione per iPhone.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Tdd iPhone For Dummies Tdd iPhone For Dummies Presentation Transcript

  • Does it work?
  • I’m not here to convince you
  • Dry and easy to maintain
  • Better form of documentation
  • Protect
  • Tdd?
  • Tdd? Test-driven development (TDD) is a software development technique that relies on the repetition of a very short development cycle http://en.wikipedia.org/wiki/Test-driven_development
  • Tdd? first the developer writes a failing automated test case that defines a desired improvement or new function http://en.wikipedia.org/wiki/Test-driven_development
  • Tdd? then produces code to pass that test http://en.wikipedia.org/wiki/Test-driven_development
  • Tdd? and finally refactors the new code to acceptable standard http://en.wikipedia.org/wiki/Test-driven_development
  • Unit Tests? A test is not a unit test if: Michael Feathers
  • Unit Tests? It talks to a database Michael Feathers
  • Unit Tests? It communicates across the network Michael Feathers
  • Unit Tests? It touches the file system Michael Feathers
  • Unit Tests? You have to do things to your environment to run it (eg, change config files) Michael Feathers
  • Unit Tests? Tests that do this are integration tests Michael Feathers
  • Automatic Testing Lifecycle Steps Fixture Setup
  • Automatic Testing Lifecycle Steps Fixture Setup SUT Exercise SUT
  • Automatic Testing Lifecycle Steps Fixture Setup SUT Exercise SUT Verify Result
  • Automatic Testing Lifecycle Steps Fixture Setup Exercise SUT Verify Result Fixture TearDown
  • What about iPhone Dev?
  • Unit Testing for iPhone
  • Former SenTestingKit OCUnit
  • TestCase definition #import <SenTestingKit/SenTestingKit.h> #import "RpnCalculator.h" @interface RpnCalculatorTestCase : SenTestCase { ! RpnCalculator* rpnCalculator; } @end
  • TestCase definition #import <SenTestingKit/SenTestingKit.h> #import "RpnCalculator.h" @interface RpnCalculatorTestCase : SenTestCase { ! RpnCalculator* rpnCalculator; } @end
  • TestCase Implementation @implementation RpnCalculatorTestCase -(void)setUp{ ! rpnCalculator = [[RpnCalculator alloc]init]; } -(void)testShouldDisplayTwoNumbersWhenNumbersAreSeparatedByEnter{ ! [rpnCalculator put:@"1"]; ! [rpnCalculator put:@"enter"]; ! [rpnCalculator put:@"2"];! ! ! STAssertEqualObjects(@"1n2",rpnCalculator.display,nil); } -(void)tearDown{ [rpnCalculator release]; }
  • Fixture Setup @implementation RpnCalculatorTestCase -(void)setUp{ ! rpnCalculator = [[RpnCalculator alloc]init]; } -(void)testShouldDisplayTwoNumbersWhenNumbersAreSeparatedByEnter{ ! [rpnCalculator put:@"1"]; ! [rpnCalculator put:@"enter"]; ! [rpnCalculator put:@"2"];! ! ! STAssertEqualObjects(@"1n2",rpnCalculator.display,nil); } -(void)tearDown{ [rpnCalculator release]; }
  • Exercise SUT @implementation RpnCalculatorTestCase -(void)setUp{ ! rpnCalculator = [[RpnCalculator alloc]init]; } -(void)testShouldDisplayTwoNumbersWhenNumbersAreSeparatedByEnter{ ! [rpnCalculator put:@"1"]; ! [rpnCalculator put:@"enter"]; ! [rpnCalculator put:@"2"];! ! ! STAssertEqualObjects(@"1n2",rpnCalculator.display,nil); } -(void)tearDown{ [rpnCalculator release]; }
  • Verify Result @implementation RpnCalculatorTestCase -(void)setUp{ ! rpnCalculator = [[RpnCalculator alloc]init]; } -(void)testShouldDisplayTwoNumbersWhenNumbersAreSeparatedByEnter{ ! [rpnCalculator put:@"1"]; ! [rpnCalculator put:@"enter"]; ! [rpnCalculator put:@"2"];! ! ! STAssertEqualObjects(@"1n2",rpnCalculator.display,nil); } -(void)tearDown{ [rpnCalculator release]; }
  • Fixture Teardown @implementation RpnCalculatorTestCase -(void)setUp{ ! rpnCalculator = [[RpnCalculator alloc]init]; } -(void)testShouldDisplayTwoNumbersWhenNumbersAreSeparatedByEnter{ ! [rpnCalculator put:@"1"]; ! [rpnCalculator put:@"enter"]; ! [rpnCalculator put:@"2"];! ! ! STAssertEqualObjects(@"1n2",rpnCalculator.display,nil); } -(void)tearDown{ [rpnCalculator release]; }
  • Assertions #define STAssertNil(a1, description, ...) #define STAssertNotNil(a1, description, ...) #define STAssertTrue(expression, description, ...) #define STAssertFalse(expression, description, ...) #define STAssertEqualObjects(a1, a2, description, ...) #define STAssertEquals(a1, a2, description, ...) #define STFail(description, ...) #define STAssertTrueNoThrow(expression, description, ...) #define STAssertFalseNoThrow(expression, description, ...) //....
  • Xcode integration
  • Xcode integration
  • Presentation separate from logic
  • Presentation separate from logic
  • Presentation
  • Logic
  • Test
  • Xcode integration
  • Xcode integration
  • What if I have to access network...
  • Or I have correlated components..
  • Mock it!
  • Mock it! [...] mock objects are simulated objects that mimic the behavior of real objects in controlled ways
  • OCMock http://www.mulle-kybernetik.com/software/OCMock/
  • Stubs vs Mocks Mocks Stubs
  • Stub - (void)testReturnsStubbedReturnValue { ! mock = [OCMockObject mockForClass:[NSString class]]; [[[mock stub] andReturn:@"megamock"] lowercaseString]; id returnValue = [mock lowercaseString]; ! STAssertEqualObjects(@"megamock", returnValue, nil); }
  • Collaboration SOAPMessage XMLString SOAPClient send SOAPChannel post
  • Collaboration SOAPMessage XMLString SOAPClient send SOAPChannel post
  • Collaboration SOAPMessage XMLString SOAPClient send SOAPChannel post
  • Mock static const NSString * RawSOAPMessage = @"<ENV:evn xmlns:ENV="http://www.w3.org/.... - (void)testClientShouldSendMessage{ ! id msgMock = [OCMockObject mockForClass:[SOAPMessage class]]; ! [[[msgMock expect] andReturn:RawSOAPMessage] XMLString]; ! id channelMock = [OCMockObject mockForClass:[SOAPChannel class]]; ! [[[channelMock expect] andReturn:TRUE] send]; ! SOAPClient *client = [SOAPClient initWith:channelMock]; ! ! [client sendMessage:msgMock]; ! [msgMock verify]; ! [channelMock verify]; }
  • Mockery static const NSString * RawSOAPMessage = @"<ENV:evn xmlns:ENV="http://www.w3.org/.... - (void)testClientShouldSendMessage{ ! id msgMock = [OCMockObject mockForClass:[SOAPMessage class]]; ! [[[msgMock expect] andReturn:RawSOAPMessage] XMLString]; ! id channelMock = [OCMockObject mockForClass:[SOAPChannel class]]; ! [[[channelMock expect] andReturn:TRUE] send]; ! SOAPClient *client = [SOAPClient initWith:channelMock]; ! ! [client sendMessage:msgMock]; ! [msgMock verify]; ! [channelMock verify]; }
  • Exercise SUT static const NSString * RawSOAPMessage = @"<ENV:evn xmlns:ENV="http://www.w3.org/.... - (void)testClientShouldSendMessage{ ! id msgMock = [OCMockObject mockForClass:[SOAPMessage class]]; ! [[[msgMock expect] andReturn:RawSOAPMessage] XMLString]; ! id channelMock = [OCMockObject mockForClass:[SOAPChannel class]]; ! [[[channelMock expect] andReturn:TRUE] send]; ! SOAPClient *client = [SOAPClient initWith:channelMock]; ! ! [client sendMessage:msgMock]; ! [msgMock verify]; ! [channelMock verify]; }
  • Verify static const NSString * RawSOAPMessage = @"<ENV:evn xmlns:ENV="http://www.w3.org/.... - (void)testClientShouldSendMessage{ ! id msgMock = [OCMockObject mockForClass:[SOAPMessage class]]; ! [[[msgMock expect] andReturn:RawSOAPMessage] XMLString]; ! id channelMock = [OCMockObject mockForClass:[SOAPChannel class]]; ! [[[channelMock expect] andReturn:TRUE] send]; ! SOAPClient *client = [SOAPClient initWith:channelMock]; ! ! [client sendMessage:msgMock]; ! [msgMock verify]; ! [channelMock verify]; }
  • What’s wrong with Unit Testing?
  • TEST
  • Tdd isn’t about tests, but about behaviors and specifications
  • A spoonful of syntactic sugar...
  • A spoonful of syntactic sugar... Behavior Driven Development
  • should insted of test matchers instead of Assert
  • Bdd framework for iPhone Dev...
  • Bdd framework for iPhone Dev...
  • Spec Example -(void)before { ! [SpecHelper loginAsAdmin]; } -(void)itShouldAddAUser { ! [app.navigationButton touch]; ! [[app.textField.with placeholder:@"First Name"] setText:@"Brian"]; ! [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"]; ! [[app.textField.with placeholder:@"Email"] setText:@"b@g.com"]; ! [[app.textField placeholder:@"Username"] setText:@"bkuser"]; ! [[app.textField placeholder:@"Password"] setText:@"test"]; ! [[app.textField placeholder:@"Confirm"] setText:@"test"]; ! [[app.navigationButton.label text:@"Save"] touch]; ! [app timeout:1].alertView.should.not.exist; ! [[app.tableView.label text:@"Brian Knorr"] should].exist; } -(void)after { ! [SpecHelper logout]; }
  • Fixture Setup -(void)before { ! [SpecHelper loginAsAdmin]; } -(void)itShouldAddAUser { ! [app.navigationButton touch]; ! [[app.textField.with placeholder:@"First Name"] setText:@"Brian"]; ! [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"]; ! [[app.textField.with placeholder:@"Email"] setText:@"b@g.com"]; ! [[app.textField placeholder:@"Username"] setText:@"bkuser"]; ! [[app.textField placeholder:@"Password"] setText:@"test"]; ! [[app.textField placeholder:@"Confirm"] setText:@"test"]; ! [[app.navigationButton.label text:@"Save"] touch]; ! [app timeout:1].alertView.should.not.exist; ! [[app.tableView.label text:@"Brian Knorr"] should].exist; } -(void)after { ! [SpecHelper logout]; }
  • Exercise SUT -(void)before { ! [SpecHelper loginAsAdmin]; } -(void)itShouldAddAUser { ! [app.navigationButton touch]; ! [[app.textField.with placeholder:@"First Name"] setText:@"Brian"]; ! [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"]; ! [[app.textField.with placeholder:@"Email"] setText:@"b@g.com"]; ! [[app.textField placeholder:@"Username"] setText:@"bkuser"]; ! [[app.textField placeholder:@"Password"] setText:@"test"]; ! [[app.textField placeholder:@"Confirm"] setText:@"test"]; ! [[app.navigationButton.label text:@"Save"] touch]; ! [app timeout:1].alertView.should.not.exist; ! [[app.tableView.label text:@"Brian Knorr"] should].exist; } -(void)after { ! [SpecHelper logout]; }
  • Verify Result -(void)before { ! [SpecHelper loginAsAdmin]; } -(void)itShouldAddAUser { ! [app.navigationButton touch]; ! [[app.textField.with placeholder:@"First Name"] setText:@"Brian"]; ! [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"]; ! [[app.textField.with placeholder:@"Email"] setText:@"b@g.com"]; ! [[app.textField placeholder:@"Username"] setText:@"bkuser"]; ! [[app.textField placeholder:@"Password"] setText:@"test"]; ! [[app.textField placeholder:@"Confirm"] setText:@"test"]; ! [[app.navigationButton.label text:@"Save"] touch]; ! [app timeout:1].alertView.should.not.exist; ! [[app.tableView.label text:@"Brian Knorr"] should].exist; } -(void)after { ! [SpecHelper logout]; }
  • Fixture Teardown -(void)before { ! [SpecHelper loginAsAdmin]; } -(void)itShouldAddAUser { ! [app.navigationButton touch]; ! [[app.textField.with placeholder:@"First Name"] setText:@"Brian"]; ! [[app.textField.with placeholder:@"Last Name"] setText:@"Knorr"]; ! [[app.textField.with placeholder:@"Email"] setText:@"b@g.com"]; ! [[app.textField placeholder:@"Username"] setText:@"bkuser"]; ! [[app.textField placeholder:@"Password"] setText:@"test"]; ! [[app.textField placeholder:@"Confirm"] setText:@"test"]; ! [[app.navigationButton.label text:@"Save"] touch]; ! [app timeout:1].alertView.should.not.exist; ! [[app.tableView.label text:@"Brian Knorr"] should].exist; } -(void)after { ! [SpecHelper logout]; }
  • Run On Simulator
  • No XCode Integration Yet
  • Conclusions
  • The Market Asks For Apps
  • More Apps...
  • More Apps...
  • More Apps!
  • Lot to Improve
  • Be Good Kids:
  • Test First!
  • Reclame http://milano-xpug.pbworks.com/ http://tech.groups.yahoo.com/group/milano-xpug/
  • Questions?