Taking a Test Drive: iOS Dev UK guide to TDD

  • 1,764 views
Uploaded on

Presentation given at iOS Dev UK, Aberystwyth, in September 2011 on the benefits of test-driven development.

Presentation given at iOS Dev UK, Aberystwyth, in September 2011 on the benefits of test-driven development.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,764
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
18
Comments
0
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • You don’t want to be this guy. More importantly, you don’t want to be the guy who caused this.\nNow we don’t know what caused this\n
  • I want to tell a quick story here... not to pick on Microsoft but I find this story entertaining.\nDecember 31, 2008 all Zunes hang on last day of leap year.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Transcript

  • 1. TAKING A TEST DRIVE: USING TDD TO WRITE AN IOS APP Graham Lee, professional in-betweener @iamleeg
  • 2. TESTING: GOALS Cost Time Detected• validate code behaviour Time Requirements Architecture Construction System After introduced Test Release• discover defects Requirements 1 3 5-10 10 10-100• verify fixes Architecture - 1 10 15 25-100• detect regressions Construction - - 1 10 10-25
  • 3. TESTING: GOALS Cost Time Detected• validate code behaviour Time Requirements Architecture Construction System After introduced Test Release• discover defects Requirements 1 3 5-10 10 10-100• verify fixes Architecture - 1 10 15 25-100• detect regressions Construction - - 1 10 10-25 Unit Testing
  • 4. THE TESTING LANDSCAPE System Test Beta/Acceptance TestingBlack Box Pen/fuzz Testing Integration Testing GUI TestingGrey Box Unit testing (undirected) Source AuditWhite Box Class Component System Static Analysis, Debugging
  • 5. THE TESTING LANDSCAPE System Test Beta/Acceptance TestingBlack Box Pen/fuzz Testing Integration Testing GUI Testing TDDGrey Box Unit testing (undirected) Source AuditWhite Box Class Component System Static Analysis, Debugging
  • 6. TDD - WHAT IT ACHIEVES• Imposes black-box thinking for the developer• Guides design and implementation• YAGNI• Provides a safety net for future development• Assists accurate planning
  • 7. FIND BUGS BEFORE…
  • 8. …YOUR CUSTOMERS DO © 2009 Microsoft
  • 9. TDD != [BULLET SILVERCOLOR]• Can’t ensure the developer understood requirements• Or that the requirements remained static• Doesn’t guarantee successful integration• Takes time
  • 10. HOW TDD WORKS
  • 11. HOW TDD WORKS RED
  • 12. HOW TDD WORKS RED GREEN
  • 13. HOW TDD WORKS RED GREEN REFACTOR
  • 14. HOW TDD WORKS RED Well, maybe a bit of brown... GREEN REFACTOR
  • 15. TEST DESIGN- (void)setUp { gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar]; comps = [[NSDateComponents alloc] init];} Common stuff here- (void)tearDown { [gregorianCalendar release]; gregorianCalendar = nil; [comps release]; comps = nil;}- (void)testDatesOnTheSameDayAreConsideredSame { //...}- (void)testCloseDatesOnSeparateDaysAreNotSame {} //... These all independent- (void)testSameDayInDifferentYearsAreNotTheSame {} //... short, readable, fast
  • 16. TESTABLE CODE
  • 17. TESTABLE CODE• Small, focussed classes, that contain…
  • 18. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect
  • 19. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect• Any side-effects are few and easy to predict
  • 20. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect• Any side-effects are few and easy to predict• Helper data passed in, not discovered
  • 21. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect• Any side-effects are few and easy to predict• Helper data passed in, not discovered• Low “cyclomatic complexity”
  • 22. DESIGN CONSEQUENCES
  • 23. CLASSES DO NOT LIVE IN ISOLATION
  • 24. CLASSES DO NOT LIVE IN ISOLATION
  • 25. CLASSES DO NOT LIVE IN ISOLATION
  • 26. CLASSES DO NOT LIVE IN ISOLATION
  • 27. CLASSES DO NOT LIVE IN ISOLATION
  • 28. CLASSES DO NOT LIVE IN ISOLATION
  • 29. CLASSES DO NOT LIVE IN ISOLATION
  • 30. CLASSES DO NOT LIVE IN ISOLATION
  • 31. CLASSES DO NOT LIVE IN ISOLATION
  • 32. CLASSES DO NOT LIVE IN ISOLATION
  • 33. ViewController Model CLASSES DO NOT LIVE IN ISOLATION
  • 34. FAKE OBJECTS• For when state is important• Remove “internal” complexity• Provide non-standard visibility• Keeptrack of changes made from outside• Examples: Core Data, network, filesystem
  • 35. FAKE OBJECTS• For when state is important• Remove “internal” complexity• Provide non-standard visibility• Keeptrack of changes made from outside• Examples: Core Data, network, filesystem
  • 36. FAKE OBJECTS A protocol works well here• For when state is important• Remove “internal” complexity• Provide non-standard visibility• Keeptrack of changes made from outside• Examples: Core Data, network, filesystem
  • 37. HERE’S A FAKE OBJECT@interface FakeNotificationCenter : NSObject { NSMutableDictionary *dictionary;}- (void)addObserver: (id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;- (void)removeObserver: (id)observer;- (BOOL)hasObject: (id)observer forNotification: (NSString *)aName;@end
  • 38. HERE’S A FAKE OBJECT@implementation FakeNotificationCenter- (id)init { self = [super init]; if (self) { dictionary = [[NSMutableDictionary alloc] init]; } return self;}- (void)addObserver: (id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject { [dictionary setObject: observer forKey: aName];}- (void)removeObserver:(id)observer { [[dictionary copy] enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) { if ([obj isEqual: observer]) { [dictionary removeObjectForKey: key]; } }];}- (BOOL)hasObject:(id)observer forNotification:(NSString *)aName { return [[dictionary objectForKey: aName] isEqual: observer];}@end
  • 39. …AND HERE’S THE TEST…- (void)testStoreSubscribesToLowMemoryNotification { [store registerForMemoryWarnings: (NSNotificationCenter *)center]; STAssertTrue([center hasObject: store forNotification: UIApplicationDidReceiveMemoryWarningNotification], @"store should haveregistered for the notification");}
  • 40. …AND THE CODE- (void)registerForMemoryWarnings:(NSNotificationCenter *)center { [center addObserver: self selector: @selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object: nil];}
  • 41. MOCK OBJECTS• For when behaviour is important• Recordwhat messages with what parameters are expected• Verify that this expectation is met
  • 42. MOCK OBJECTS• For when behaviour is important• Recordwhat messages with what parameters are expected• Verify that this expectation is met
  • 43. HERE’S (THE SAME) TEST- (void)testStoreRegistersForMemoryWarnings{ id center = [OCMockObject mockForClass: [NSNotificationCenter class]]; [[center expect] addObserver: store selector: [OCMArg anyPointer] name:UIApplicationDidReceiveMemoryWarningNotification object: [OCMArg any]]; [store registerForMemoryWarnings: center]; [center verify];}
  • 44. CONCLUSIONS• Test-driven development helps understand and improve code quality• …but it’s mainly a design thing• TDD code has a tendency towards small, independent, reusable modules of size ~1 class
  • 45. QUESTIONS?