48
Unit Testing in iOS featuring OCUnit, GHUnit & OCMock works for OS X too! @hpique

Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Unit Testing in iOSfeaturing OCUnit, GHUnit & OCMock

works for OS X too!

@hpique

Page 2: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

The sad fate of developers who don’t write unit tests

Page 3: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Agenda

• Unit testing

• OCUnit

• GHUnit

• OCMock

• Profit!

Page 4: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

unit test=

code that tests a single unit of code

Page 5: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

- (void) testColorFromPointAndSize_SizeZero{ // Prepare input CGSize size = CGSizeZero; CGPoint point = CGPointZero;

// Do something UIColor *color = [_viewController colorFromPoint:point andSize:size]; // Validate output STAssertNil(color, @"Color must be nil when size is zero");}

Hey look! A unit test!

Page 6: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Reasons not to unit test

Page 7: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

...

Page 8: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

ReasonsExcuses not to unit test

Page 9: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Excuses

• “I don’t need it”

• “Deadline is too tight”

• “It’s not applicable for this [project|class|method]”

• “Unit testing in Xcode sucks”

Page 10: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Reasons to unit test• Fix bugs early

• Refine design

• Easier to make changes

• Instant gratification :)

• Useful documentation

• Reduce testing time

Page 11: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

quality code and testable code are best buds

Page 12: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

When?

• After writing code

• Before writing code (TDD)

• After fixing a bug

Page 13: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

DefinitionsTest Suite

Test Case Test CaseTest Case

SetUp

TearDown

Page 14: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Agenda

• Unit testing

• OCUnit

• GHUnit

• OCMock

• Profit!

Page 15: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

OCUnit

• De-facto unit testing framework for Obj-C

• Xcode provides native support

Page 16: Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Page 17: Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Page 18: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

+N

Page 19: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

#import <SenTestingKit/SenTestingKit.h>

@interface HelloWorldTests : SenTestCase

@end

@implementation HelloWorldTests

- (void)setUp{ [super setUp]; // Set-up code here.}

- (void)tearDown{ // Tear-down code here. [super tearDown];}

- (void)testExample{ STFail(@"Unit tests are not implemented yet in HelloWorldTests");}

@end

Page 20: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Writing tests with OCUnit

• Each Test Suite is a class that inherits from SenTestCase

• Each Test Case is a method with prefix test

• setUp & tearDown are optional

Page 21: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

+U

Page 22: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Console output2011-12-09 12:43:01.394 HelloWorld[2858:fb03] Applications are expected to have a root view controller at the end of application launchTest Suite 'All tests' started at 2011-12-09 11:43:01 +0000Test Suite '/Users/hermespique/Library/Developer/Xcode/DerivedData/HelloWorld-ezilismrgmrzecbbsndapbyeczre/Build/Products/Debug-iphonesimulator/HelloWorldTests.octest(Tests)' started at 2011-12-09 11:43:01 +0000Test Suite 'HelloWorldTests' started at 2011-12-09 11:43:01 +0000Test Case '-[HelloWorldTests testExample]' started./Users/hermespique/Documents/workspace/HelloWorld/HelloWorldTests/HelloWorldTests.m:33: error: -[HelloWorldTests testExample] : Unit tests are not implemented yet in HelloWorldTestsTest Case '-[HelloWorldTests testExample]' failed (0.000 seconds).Test Suite 'HelloWorldTests' finished at 2011-12-09 11:43:01 +0000.Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.000) secondsTest Suite '/Users/hermespique/Library/Developer/Xcode/DerivedData/HelloWorld-ezilismrgmrzecbbsndapbyeczre/Build/Products/Debug-iphonesimulator/HelloWorldTests.octest(Tests)' finished at 2011-12-09 11:43:01 +0000.Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.000) secondsTest Suite 'All tests' finished at 2011-12-09 11:43:01 +0000.Executed 1 test, with 1 failure (0 unexpected) in 0.000 (0.001) seconds

Page 23: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

OCUnit MacrosSTAssertEqualObjects(a1, a2, description, ...)STAssertEquals(a1, a2, description, ...)STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...)STFail(description, ...)STAssertNil(a1, description, ...)STAssertNotNil(a1, description, ...)STAssertTrue(expr, description, ...)STAssertTrueNoThrow(expr, description, ...)STAssertFalse(expr, description, ...)STAssertFalseNoThrow(expr, description, ...)STAssertThrows(expr, description, ...)STAssertThrowsSpecific(expr, specificException, description, ...)STAssertThrowsSpecificNamed(expr, specificException, aName, description, ...)STAssertNoThrow(expr, description, ...)STAssertNoThrowSpecific(expr, specificException, description, ...)STAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...)

Page 24: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Most used macrosSTAssertTrue(expr, description, ...)

STAssertFalse(expr, description, ...)

STAssertNil(a1, description, ...)

STAssertNotNil(a1, description, ...)

STAssertEqualObjects(a1, a2, description, ...)

STAssertEquals(a1, a2, description, ...)

STFail(description, ...)

STAssertThrows(expr, description, ...)

Page 25: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Let’s see some code!

github.com/hpique/Unit-Testing-in-iOS-Sample-Code

Page 26: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Agenda

• Unit testing

• OCUnit

• GHUnit

• OCMock

• Profit!

Page 27: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

GHUnit• The other Unit Testing framework for

Obj-C

• Open-source: github.com/gabriel/gh-unit

• GUI!

• No Xcode native support

• Compatible with OCUnit

Page 28: Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Page 29: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

#import <GHUnitIOS/GHUnit.h>

@interface ExampleTest : GHTestCase@end

@implementation ExampleTest

- (BOOL)shouldRunOnMainThread { return NO;}

- (void)setUpClass { // Run at start of all tests in the class}

- (void)setUp { // Run before each test method}

- (void)tearDown { // Run after each test method}

- (void)tearDownClass { // Run at end of all tests in the class}

- (void)testFoo { NSString *a = @"foo"; GHAssertNotNil(a, nil);}

@end

Page 30: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

If you’re into macros...GHAssertNoErr(a1, description, ...)GHAssertErr(a1, a2, description, ...)GHAssertNotNULL(a1, description, ...)GHAssertNULL(a1, description, ...)GHAssertNotEquals(a1, a2, description, ...)GHAssertNotEqualObjects(a1, a2, desc, ...)GHAssertOperation(a1, a2, op, description, ...)GHAssertGreaterThan(a1, a2, description, ...)GHAssertGreaterThanOrEqual(a1, a2, description, ...)GHAssertLessThan(a1, a2, description, ...)GHAssertLessThanOrEqual(a1, a2, description, ...)GHAssertEqualStrings(a1, a2, description, ...)GHAssertNotEqualStrings(a1, a2, description, ...)GHAssertEqualCStrings(a1, a2, description, ...)GHAssertNotEqualCStrings(a1, a2, description, ...)GHAssertEqualObjects(a1, a2, description, ...)

GHAssertEquals(a1, a2, description, ...)GHAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right))GHAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...)GHFail(description, ...)GHAssertNil(a1, description, ...)GHAssertNotNil(a1, description, ...)GHAssertTrue(expr, description, ...)GHAssertTrueNoThrow(expr, description, ...)GHAssertFalse(expr, description, ...)GHAssertFalseNoThrow(expr, description, ...)GHAssertThrows(expr, description, ...)GHAssertThrowsSpecific(expr, specificException, description, ...)GHAssertThrowsSpecificNamed(expr, specificException, aName, description, ...)GHAssertNoThrow(expr, description, ...)GHAssertNoThrowSpecific(expr, specificException, description, ...)GHAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...)

Page 31: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

GHUnitAsyncTestCase#import <GHUnitIOS/GHUnit.h>

@interface AsyncTest : GHAsyncTestCase { }@end

@implementation AsyncTest

- (void)testURLConnection { [self prepare]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; [self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.0]; }

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testURLConnection)];}

@end

Page 32: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Configure GHUnit

1. Create target2. Add GHUnitiOS.framework

2.1.and QuartzCore.framework!3. Modify Other Linker Flags4. Change AppDelegate

Page 33: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

1. Create target

Page 34: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

1. Create target

Page 35: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

2. Add GHUnitiOS.framework 1. Download from github & unzip2. > cd gh-unit/Project-iOS3. > make

orDownload the latest stable framework from github downloads

Page 36: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

3. Modify Other Link Flags

• Add -all_load

• Add -ObjC

Page 37: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

4. Change AppDelegate

int main(int argc, char *argv[]){ @autoreleasepool { return UIApplicationMain(argc, argv, nil, @"GHUnitIOSAppDelegate"); }}

1. Remove default AppDelegate

2. Modify main.m:

Page 38: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

+B

Page 39: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Let’s see some code!

github.com/hpique/Unit-Testing-in-iOS-Sample-Code

Page 40: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

OCUnit vs GHUnitOCUnit GHUnit

Xcode integration Built-in Manual

Results ConsoleContextual

ConsoleGUI

Development More macrosGHAsyncTestCase

Execution Everything Everything, selection or failed

Page 41: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Using OCUnit tests in GHUnit target

1. Add OCUnit tests to target2. Add tested files to target3. Add SenTestKit.framework 4. Add this to Framework Search Paths

(order matters):

$(SDKROOT)/Developer/Library/Frameworks$(DEVELOPER_LIBRARY_DIR)/Frameworks

Page 42: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Agenda

• Unit testing

• OCUnit

• GHUnit

• OCMock

• Profit!

Page 43: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

mock object=

simulated object that mimics the behavior

of a real object in controlled ways

Page 44: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

When to mock an object?

• supplies non-deterministic results (ie: sensors)

• has states that are difficult to create or reproduce (ie: a network error)

• is slow (ie: database)

• does not yet exist or may change behavior

• to avoid writing “test code”

Page 45: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

OCMock

• De-facto mocking framework for Obj-C

• Open-source: github.com/erikdoe/ocmock

• mock objects on the fly via the trampoline pattern

• Complementary with OCUnit & GHUnit

Page 46: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Hey look! Mock objects!- (void) testHandleGesture{ // Prepare input and state id viewMock = [OCMockObject partialMockForObject:_viewController.view]; CGRect viewFrame = CGRectMake(0, 0, 320, 480); [[[viewMock stub] andReturnValue:OCMOCK_VALUE(viewFrame)] frame]; _viewController.view = viewMock;

UIGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] init]; id gestureMock = [OCMockObject partialMockForObject:gesture]; CGPoint gesturePoint = CGPointMake(viewFrame.size.width / 2, viewFrame.size.height / 2); [[[gestureMock stub] andReturnValue:OCMOCK_VALUE(gesturePoint)] locationInView:[OCMArg any]]; // Do something that changes state [_viewController handleGesture:gestureMock];

// Validate state UIColor *expectedColor = [UIColor colorWithRed:0.5 green:0.5 blue:0 alpha:1]; UIColor *color = _viewController.view.backgroundColor; [self assertEqualsColor:expectedColor toColor:color];}

Page 47: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Let’s see some code!

github.com/hpique/Unit-Testing-in-iOS-Sample-Code

Page 48: Unit testing in iOS featuring OCUnit, GHUnit & OCMock

Thanks!

@hpique