Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Taking a Test Drive: iOS Dev UK guide to TDD

2,182 views

Published on

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

Published in: Technology

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?

×