Slide 1

Slide 1 text

UNIT TESTING jamie sa @JAMEX for an iOS developer Saturday, October 20, 12

Slide 2

Slide 2 text

UNIT TESTING IS NOT FOR IOS Unit Testing is awesome for guaranteeing consistent behavior of infrastructure. - bbum 2005 Saturday, October 20, 12

Slide 3

Slide 3 text

@implementation BrowseOverflowViewControllerTests { BrowseOverflowViewController *viewController; UITableView *tableView; id dataSource; UINavigationController *navController; SEL realViewDidAppear, testViewDidAppear; SEL realViewWillDisappear, testViewWillDisappear; SEL realUserDidSelectTopic, testUserDidSelectTopic; BrowseOverflowObjectConfiguration *objectConfiguration; } + (void)swapInstanceMethodsForClass: (Class) cls selector: (SEL) sel1 andSelector: (SEL) sel2 { Method method1 = class_getInstanceMethod(cls, sel1); Method method2 = class_getInstanceMethod(cls, sel2); method_exchangeImplementations(method1, method2); } Method Swizzling Saturday, October 20, 12

Slide 4

Slide 4 text

@implementation BrowseOverflowViewControllerTests { BrowseOverflowViewController *viewController; UITableView *tableView; id dataSource; UINavigationController *navController; SEL realViewDidAppear, testViewDidAppear; SEL realViewWillDisappear, testViewWillDisappear; SEL realUserDidSelectTopic, testUserDidSelectTopic; BrowseOverflowObjectConfiguration *objectConfiguration; } + (void)swapInstanceMethodsForClass: (Class) cls selector: (SEL) sel1 andSelector: (SEL) sel2 { Method method1 = class_getInstanceMethod(cls, sel1); Method method2 = class_getInstanceMethod(cls, sel2); method_exchangeImplementations(method1, method2); } Method Swizzling in runtime.h OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0); Saturday, October 20, 12

Slide 5

Slide 5 text

UNIT TESTING SLOWS DOWN DEVELOPMENT PROCESS Unit Testing is core part of ANY Agile best practice. Saturday, October 20, 12

Slide 6

Slide 6 text

Saturday, October 20, 12

Slide 7

Slide 7 text

UNIT TESTS ARE A FORM OF SAMPLE CODE Saturday, October 20, 12

Slide 8

Slide 8 text

- (void)testArticleWithIncompletedAttachmentShouldBeDecorated { NSArray *changedArticleReps = [self loadDataFile:@"PostWithIncompleteAttachmentInformation"]; STAssertNotNil(changedArticleReps, @"should be a JSON array"); NSArray *touchedArticles = [WAArticle insertOrUpdateObjectsUsingContext:context withRemoteResponse:changedArticleReps usingMapping:nil options:IRManagedObjectOptionIndividualOperations]; WAArticle *article = [touchedArticles objectAtIndex:0]; STAssertEquals((NSUInteger)20, [article.files count], @"attachments should be decorated to 20"); NSFetchRequest *fetchRequest = [[WADataStore defaultStore] newFetchRequestForFilesInArticle:article]; NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:article.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; NSError *fetchError = nil; if (![fetchedResultsController performFetch:&fetchError]) NSLog(@"Error fetching: %@", fetchError); STAssertEquals((NSUInteger)20, [[fetchedResultsController fetchedObjects] count], @"Should be 20."); for (WAFile *photo in [fetchedResultsController fetchedObjects]) { STAssertEqualObjects(@"public.jpeg", photo.resourceType, @"Type must be jpeg."); STAssertEqualObjects(@"image", photo.remoteResourceType, @"Must be an image."); STAssertNotNil(photo.smallThumbnailURL, @"Small thumbnail required"); STAssertNotNil(photo.thumbnailURL, @"Medium thumbnail required"); } Saturday, October 20, 12

Slide 9

Slide 9 text

USE OCMOCK OCMATCHER Saturday, October 20, 12

Slide 10

Slide 10 text

USE OCMOCK OCHAMCREST Saturday, October 20, 12

Slide 11

Slide 11 text

- (void)testOpenConnectionFail { __block BOOL complete = NO; __weak WAWebSocket *wSocket = webSocket; [[[mockSocket expect] andDo:^(NSInvocation *invocation) { [wSocket performSelector:@selector(webSocket:didFailWithError:) withObject:nil }] open]; [webSocket replaceWebSocketConnection:(SRWebSocket*)mockSocket]; [webSocket openConnectionOnSucces:^{ complete = YES; STFail(@"Websocket connection should fail to be opened."); } onFailure:^(NSError *error) { complete = YES; // success }]; while (complete == NO && [asyncWaitUntil timeIntervalSinceNow] > 0) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:asyncWaitUntil]; } if (complete == NO) { STFail(@"Websocket connection should be opened on time."); } [mockSocket verify]; } Saturday, October 20, 12

Slide 12

Slide 12 text

IT’S FASTER THAN WRITING CODE WITHOUT TESTS Saturday, October 20, 12

Slide 13

Slide 13 text

It’s your turn NOW. Saturday, October 20, 12