ios testing

36
Testing in iOS 10.01.2013 by Tomasz Janeczko

Upload: tomasz-janeczko

Post on 11-May-2015

948 views

Category:

Technology


2 download

DESCRIPTION

Testing in iOS using Kiwi and OCMock frameworks

TRANSCRIPT

Page 1: iOS testing

Testing in iOS10.01.2013 by Tomasz Janeczko

Page 2: iOS testing

About me

Tomasz Janeczko

• iOS developer in Kainos

• Enthusiast of business, electronics, Rails & Heroku

• Organizer of first App Camp in UK and PL

Page 3: iOS testing

So let’s talk about testing.

Page 4: iOS testing

Why we test?

Page 5: iOS testing
Page 6: iOS testing

So?

Page 7: iOS testing

• Reliability

• Regression

• Confidence (e.g. refactoring)

Page 8: iOS testing

Why not to test?

Page 9: iOS testing

Why not to test?

• Heavy dependence on UI

• Non-testable code

• Bad framework

Page 10: iOS testing

How to address issues

• Sample - downloading stuff from interwebz

Page 11: iOS testing

First fault

Writing tests after writing code

Page 12: iOS testing

Separation of concerns

Page 13: iOS testing

Separation of concerns

• Let’s separate out the UI code

• Same for services interaction

Page 14: iOS testing

Demo of tests

Page 15: iOS testing

Writing testsMeet Kiwi and OCMock

Page 16: iOS testing

Kiwi

• RSpec-like tests writing

• Matchers

• Cleaner and more self-descriptive code

Page 17: iOS testing

Kiwi

describe(@"Tested class", ^{

context(@"When created", ^{

it(@"should not fail", ^{ [[theValue(0) should] equal:theValue(0)]; });

});

});

Page 18: iOS testing

Kiwi

describe(@"Tested class", ^{

context(@"When created", ^{

it(@"should not fail", ^{ id viewController = [ViewController new]; [[viewController should] conformToProtocol:@protocol(UITableViewDelegate)]; });

});

});

Page 19: iOS testing

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.

Page 20: iOS testing

Compare to SenTesting Kit

[[subject  should]  equal:anObject]

compare  with

STAssertEquals(subject,  anObject,  @”Should  be  equal”);

Page 21: iOS testing

OCMock

• Mocking and stubbing library for iOS

• Quite versatile

• Makes use of NSProxy magic

Page 22: iOS testing

Sample workflows

Page 23: iOS testing

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];                });

Page 24: iOS testing

Test if calls dep methods

1. Create a mock dependency

2. Inject it

3. Call the method

4. Verify

Page 25: iOS testing

Test dependency

// Create the tested object and mock to exchange part of the functionalityviewController = [ViewController new];mockController = [OCMockObject partialMockForObject:viewController];

// Create the mock and change implementation to return our classid 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];

Page 26: iOS testing

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

Page 27: iOS testing

Accessing private methods

Page 28: iOS testing

Accessing private methods

@interface ViewController()

- (void)startDownloadingTweets;

@end

...[[mockController expect] startDownloadingTweets];

Page 29: iOS testing

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];

Page 30: iOS testing

Static method testing

• Through method swizzlingvoid  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);}

Page 31: iOS testing

Normal conditions applydespite it’s iOS & Objective--C

Page 32: iOS testing

Problems of „mobile devs”

• Pushing code with failing tests

• Lot’s of hacking together

• Weak knowledge of VCS tools - merge nightmares

Page 33: iOS testing

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

Page 34: iOS testing

Ending thoughts

• Practice!

Page 35: iOS testing

Thanks!

Page 36: iOS testing

Questions