Upload
robot-media
View
4.653
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
Unit Testing in iOSfeaturing OCUnit, GHUnit & OCMock
works for OS X too!
@hpique
The sad fate of developers who don’t write unit tests
Agenda
• Unit testing
• OCUnit
• GHUnit
• OCMock
• Profit!
unit test=
code that tests a single unit of code
- (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!
Reasons not to unit test
...
ReasonsExcuses not to unit test
Excuses
• “I don’t need it”
• “Deadline is too tight”
• “It’s not applicable for this [project|class|method]”
• “Unit testing in Xcode sucks”
Reasons to unit test• Fix bugs early
• Refine design
• Easier to make changes
• Instant gratification :)
• Useful documentation
• Reduce testing time
quality code and testable code are best buds
When?
• After writing code
• Before writing code (TDD)
• After fixing a bug
DefinitionsTest Suite
Test Case Test CaseTest Case
SetUp
TearDown
Agenda
• Unit testing
• OCUnit
• GHUnit
• OCMock
• Profit!
OCUnit
• De-facto unit testing framework for Obj-C
• Xcode provides native support
+N
#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
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
+U
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
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, ...)
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, ...)
Let’s see some code!
github.com/hpique/Unit-Testing-in-iOS-Sample-Code
Agenda
• Unit testing
• OCUnit
• GHUnit
• OCMock
• Profit!
GHUnit• The other Unit Testing framework for
Obj-C
• Open-source: github.com/gabriel/gh-unit
• GUI!
• No Xcode native support
• Compatible with OCUnit
#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
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, ...)
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
Configure GHUnit
1. Create target2. Add GHUnitiOS.framework
2.1.and QuartzCore.framework!3. Modify Other Linker Flags4. Change AppDelegate
1. Create target
1. Create target
2. Add GHUnitiOS.framework 1. Download from github & unzip2. > cd gh-unit/Project-iOS3. > make
orDownload the latest stable framework from github downloads
3. Modify Other Link Flags
• Add -all_load
• Add -ObjC
4. Change AppDelegate
int main(int argc, char *argv[]){ @autoreleasepool { return UIApplicationMain(argc, argv, nil, @"GHUnitIOSAppDelegate"); }}
1. Remove default AppDelegate
2. Modify main.m:
+B
Let’s see some code!
github.com/hpique/Unit-Testing-in-iOS-Sample-Code
OCUnit vs GHUnitOCUnit GHUnit
Xcode integration Built-in Manual
Results ConsoleContextual
ConsoleGUI
Development More macrosGHAsyncTestCase
Execution Everything Everything, selection or failed
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
Agenda
• Unit testing
• OCUnit
• GHUnit
• OCMock
• Profit!
mock object=
simulated object that mimics the behavior
of a real object in controlled ways
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”
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
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];}
Let’s see some code!
github.com/hpique/Unit-Testing-in-iOS-Sample-Code
Thanks!
@hpique