Taking a Test Drive: iOS Dev UK guide to TDD

2,125 views

Published on

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

Published in: Technology
1 Comment
4 Likes
Statistics
Notes
No Downloads
Views
Total views
2,125
On SlideShare
0
From Embeds
0
Number of Embeds
37
Actions
Shares
0
Downloads
26
Comments
1
Likes
4
Embeds 0
No embeds

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
  • Taking a Test Drive: iOS Dev UK guide to TDD

    1. 1. TAKING A TEST DRIVE: USING TDD TO WRITE AN IOS APP Graham Lee, professional in-betweener @iamleeg
    2. 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. 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. 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. 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. 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. 7. FIND BUGS BEFORE…
    8. 8. …YOUR CUSTOMERS DO © 2009 Microsoft
    9. 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. 10. HOW TDD WORKS
    11. 11. HOW TDD WORKS RED
    12. 12. HOW TDD WORKS RED GREEN
    13. 13. HOW TDD WORKS RED GREEN REFACTOR
    14. 14. HOW TDD WORKS RED Well, maybe a bit of brown... GREEN REFACTOR
    15. 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. 16. TESTABLE CODE
    17. 17. TESTABLE CODE• Small, focussed classes, that contain…
    18. 18. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect
    19. 19. TESTABLE CODE• Small, focussed classes, that contain…• Short methods, each with obvious effect• Any side-effects are few and easy to predict
    20. 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. 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. 22. DESIGN CONSEQUENCES
    23. 23. CLASSES DO NOT LIVE IN ISOLATION
    24. 24. CLASSES DO NOT LIVE IN ISOLATION
    25. 25. CLASSES DO NOT LIVE IN ISOLATION
    26. 26. CLASSES DO NOT LIVE IN ISOLATION
    27. 27. CLASSES DO NOT LIVE IN ISOLATION
    28. 28. CLASSES DO NOT LIVE IN ISOLATION
    29. 29. CLASSES DO NOT LIVE IN ISOLATION
    30. 30. CLASSES DO NOT LIVE IN ISOLATION
    31. 31. CLASSES DO NOT LIVE IN ISOLATION
    32. 32. CLASSES DO NOT LIVE IN ISOLATION
    33. 33. ViewController Model CLASSES DO NOT LIVE IN ISOLATION
    34. 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. 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. 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. 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. 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. 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. 40. …AND THE CODE- (void)registerForMemoryWarnings:(NSNotificationCenter *)center { [center addObserver: self selector: @selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object: nil];}
    41. 41. MOCK OBJECTS• For when behaviour is important• Recordwhat messages with what parameters are expected• Verify that this expectation is met
    42. 42. MOCK OBJECTS• For when behaviour is important• Recordwhat messages with what parameters are expected• Verify that this expectation is met
    43. 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. 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. 45. QUESTIONS?

    ×