Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2013-01-10 iOS testing

2013-01-10 iOS testing

CocoaHeads Tricity

January 10, 2013
Tweet

More Decks by CocoaHeads Tricity

Other Decks in Programming

Transcript

  1. About me Tomasz Janeczko • iOS developer in Kainos •

    Enthusiast of business, electronics, Rails & Heroku • Organizer of first App Camp in UK and PL
  2. So?

  3. Why not to test? • Heavy dependence on UI •

    Non-testable code • Bad framework
  4. Kiwi describe(@"Tested class", ^{ context(@"When created", ^{ it(@"should not fail",

    ^{ [[theValue(0) should] equal:theValue(0)]; }); }); });
  5. Kiwi describe(@"Tested class", ^{ context(@"When created", ^{ it(@"should not fail",

    ^{ id viewController = [ViewController new]; [[viewController should] conformToProtocol:@protocol(UITableViewDelegate)]; }); }); });
  6. Matchers [subject  shouldNotBeNil] • [subject  shouldBeNil] • [[subject  should]  beIdenticalTo:(id)anObject]

    - compares id's • [[subject  should]  equal:(id)anObject] • [[subject  should]  equal:(double)aValue  withDelta: (double)aDelta] • [[subject  should]  beWithin:(id)aDistance  of:(id)aValue] • [[subject  should]  beLessThan:(id)aValue] • etc.  etc.
  7. OCMock • Mocking and stubbing library for iOS • Quite

    versatile • Makes use of NSProxy magic
  8. Classic calculator sample describe(@"Calculator",  ^{          

         context(@"with  the  numbers  60  and  5  entered",  ^{                RPNCalculator  *calculator  =  [[RPNCalculator  alloc]  init];                                beforeEach(^{                        [calculator  enter:60];                        [calculator  enter:5];                });                afterEach(^{                          [calculator  clear];                });                              it(@"returns  65  as  the  sum",  ^{                        [[theValue([calculator  add])  should]  equal:65  withDelta:.01];                });
  9. Test if calls dep methods 1. Create a mock dependency

    2. Inject it 3. Call the method 4. Verify
  10. Test dependency // Create the tested object and mock to

    exchange part of the functionality viewController = [ViewController new]; mockController = [OCMockObject partialMockForObject:viewController]; // Create the mock and change implementation to return our class id serviceMock = [OCMockObject mockForClass:[InterwebzService class]]; [[[mockController stub] andReturn:serviceMock] service]; // Define expectations [[serviceMock expect] downloadTweetsJSONWithSuccessBlock:[OCMArg any]]; // Run the tested method [viewController tweetsButtonTapped:nil]; // Verify - throws exception on failure [mockController verify];
  11. Testing one layer • Isolate dependencies • Objective-C is highly

    dynamic - we can change implementations of private methods or static methods • We can avoid IoC containers for testing
  12. Static method testing • Through separation to a method @interface

    ViewController() - (NSUserDefaults *)userDefaults; @end ... id mockDefaults = [OCMockObject mockForClass:[NSUserDefaults class]]; [[[mockDefaults expect] andReturn:@"Setting"] valueForKey:[OCMArg any]]; [[[mockController stub] andReturn:mockDefaults] userDefaults];
  13. Static method testing • Through method swizzling void  SwizzleClassMethod(Class  c,

     SEL  orig,  SEL  new)  {        Method  origMethod  =  class_getClassMethod(c,  orig);        Method  newMethod  =  class_getClassMethod(c,  new);        c  =  object_getClass((id)c);        if(class_addMethod(c,  orig,  method_getImplementation(newMethod),  method_getTypeEncoding(newMethod)))                class_replaceMethod(c,  new,  method_getImplementation(origMethod),   method_getTypeEncoding(origMethod));        else                method_exchangeImplementations(origMethod,  newMethod); }
  14. Problems of „mobile devs” • Pushing code with failing tests

    • Lot’s of hacking together • Weak knowledge of VCS tools - merge nightmares
  15. Ending thoughts • Think first (twice), then code :) •

    Tests should come first • Write the failing test, pass the test, refactor • Adequate tools can enhance your testing experience