Adding OCMock to your project:
- Step 1: Download a release from the downloads page.
- Step 2: Setup OCMock from the iOS page.
- Step 3: Add an import to your unit tests.
#import <OCMock/OCMock.h>
Contents:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
static NSString* const NOTIFICATION_OF_CLASS = @"NotificationOfClass"; | |
@class ClassA; | |
@class ClassB; | |
@protocol ClassADelegate <NSObject> | |
- (void)responsedValue:(ClassA*)class value:(NSString*)aValue; | |
@end | |
@interface ClassA : NSObject { | |
@public | |
ClassB* publicClass; | |
} | |
@property (nonatomic, assign) id delegate; | |
- (void)executeVoidMethod; | |
- (void)executeVoidMethodAndSubVoidMethod; | |
- (void)executeVoidMethodAndReturnMethod; | |
- (void)executeBlockMethod:(void(^)(NSString* returnedValue))aBlock; | |
- (NSString*)executeReturnMethodAndSubBlock; | |
- (void)executeVoidMethodAndDelegate; | |
- (void)executeVoidMethodAndNotification; | |
- (void)executeVoidMethodAndException:(NSString*)aParam; | |
- (void)executeRejectMethod; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "ClassA.h" | |
#import "ClassB.h" | |
@implementation ClassA | |
- (void)executeVoidMethod { | |
NSLog(@"Void_%@",[self class]); | |
} | |
- (void)executeVoidMethodAndSubVoidMethod { | |
if (publicClass) { | |
//Comment this code and run "testSubVoidMethod_UsingClassMock" | |
[publicClass executeVoidMethod]; | |
//End | |
} | |
} | |
- (void)executeVoidMethodAndReturnMethod { | |
if (publicClass) { | |
//You can comment these codes and run "testStubActionsAndExpect_UsingClassMock" | |
NSString* value = [publicClass executeReturnMethod]; | |
NSLog(@"%@",value); | |
//End | |
} | |
} | |
- (void)executeBlockMethod:(void(^)(NSString* returnedValue))aBlock { | |
aBlock([NSString stringWithFormat:@"Block_%@",[self class]]); | |
} | |
- (NSString*)executeReturnMethodAndSubBlock { | |
__block NSString* value = @"DefaultValue"; | |
if (publicClass) { | |
[publicClass executeBlockMethod:^(NSString *returnedValue) { | |
value = returnedValue; | |
}]; | |
} | |
return value; | |
} | |
- (void)simulateDelegate { | |
if ([_delegate respondsToSelector:@selector(responsedValue:value:)]) { | |
[_delegate responsedValue:self value:@"DelegateValue"]; | |
} | |
} | |
- (void)executeVoidMethodAndDelegate { | |
[self performSelector:@selector(simulateDelegate) | |
withObject:nil afterDelay:2]; | |
} | |
- (void)executeVoidMethodAndNotification { | |
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_OF_CLASSA | |
object:nil]; | |
} | |
- (void)simulateException:(NSString*)aParam { | |
if (!aParam) { | |
[[NSException exceptionWithName:@"ABC" reason:@"Non" userInfo:nil] raise]; | |
} | |
NSLog(@"Run fine"); | |
} | |
- (void)executeVoidMethodAndException:(NSString*)aParam { | |
@try { | |
if (!publicClass) { | |
[[NSException exceptionWithName:@"Object" reason:@"Non" userInfo:nil] raise]; | |
} | |
[publicClass simulateException:aParam]; | |
} | |
@catch (NSException *exception) { | |
NSLog(@"%@",exception); | |
} | |
@finally { | |
NSLog(@"Final"); | |
} | |
} | |
- (void)executeRejectMethod { | |
if (publicClass) { | |
//Uncomment this code and run "testRejectActions_UsingClassMock" | |
// [publicClass executeReturnMethod]; | |
} | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import "ClassA.h" | |
@interface ClassB : ClassA | |
- (NSString*)executeReturnMethod; | |
- (void)executeMethodWithOrder1; | |
- (void)executeMethodWithOrder2; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "ClassB.h" | |
@implementation ClassB | |
- (NSString*)executeReturnMethod { | |
return @"ClassB"; | |
} | |
- (void)executeMethodWithOrder1 { | |
NSLog(@"First"); | |
} | |
- (void)executeMethodWithOrder2 { | |
NSLog(@"Second"); | |
} | |
- (void)executeRejectMethod { | |
//Uncomment this code and run "testRejectActions_UsingPartialMock" | |
// [self executeReturnMethod]; | |
//End | |
} | |
@end |
2. Expect-run-verify
Example codes:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Definition of the category Test on the classA | |
@interface ClassA (PrivateMethodTest) | |
- (void)simulateException:(NSString*)aParam; | |
@end | |
- (void)testExpectRunVerify_UsingClassMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
OCMExpect([classMock simulateException:@"@congpc.ios"]); | |
object->publicClass = classMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndException:@"@congpc.ios"]; | |
//THEN | |
OCMVerifyAll(classMock); | |
} | |
- (void)testExpectRunVerify_UsingStrictMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id strictMock = OCMStrictClassMock([ClassB class]); | |
OCMExpect([strictMock simulateException:@"@congpc.ios"]); | |
object->publicClass = strictMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndException:@"@congpc.ios"]; | |
//THEN | |
OCMVerifyAll(strictMock); | |
} |
3. Verify after running
Base on the example of "Expect-Run-Verify", I rewrite as below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testVerifyAfterRunning_UsingClassMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
object->publicClass = classMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndException:@"@congpc.ios"]; | |
//THEN | |
OCMVerify([classMock simulateException:@"@congpc.ios"]); | |
} | |
- (void)testVerifyAfterRunning_UsingStrictMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMStrictClassMock([ClassB class]); | |
object->publicClass = classMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndException:@"@congpc.ios"]; | |
//THEN | |
OCMVerify([classMock simulateException:@"@congpc.ios"]); | |
} |
4. Void-Method
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma mark - Using OCMock for void method | |
- (void)testVoidMethod_UsingClassMock { | |
//GIVEN | |
id objectMock = OCMClassMock([ClassA class]); | |
//WHEN /* run code under test */ | |
[objectMock executeVoidMethod]; | |
//THEN | |
OCMVerify([objectMock executeVoidMethod]); | |
} | |
- (void)testVoidMethod_UsingClassMockAndExpect { | |
//GIVEN | |
id objectMock = OCMClassMock([ClassA class]); | |
[[objectMock expect] executeVoidMethod]; | |
//WHEN /* run code under test */ | |
[objectMock executeVoidMethod]; | |
//THEN | |
OCMVerifyAll(objectMock); | |
} | |
- (void)testVoidMethod_UsingPatialMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id objectMock = OCMPartialMock(object); | |
//WHEN /* run code under test */ | |
[object executeVoidMethod]; | |
//THEN | |
OCMVerify([objectMock executeVoidMethod]); | |
} | |
- (void)testVoidMethod_UsingPatialMockAndExpect { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id objectMock = OCMPartialMock(object); | |
[[objectMock expect] executeVoidMethod]; | |
//WHEN /* run code under test */ | |
[object executeVoidMethod]; | |
//THEN | |
OCMVerifyAll(objectMock); | |
} | |
#pragma mark Sub void method | |
- (void)testSubVoidMethod_UsingClassMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id objectMock = OCMClassMock([ClassB class]); | |
object->publicClass = objectMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndSubVoidMethod]; | |
//THEN | |
OCMVerify([objectMock executeVoidMethod]); | |
} | |
- (void)testSubVoidMethod_UsingClassMockAndExpect { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id objectMock = OCMClassMock([ClassB class]); | |
[[objectMock expect] executeVoidMethod]; | |
object->publicClass = objectMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndSubVoidMethod]; | |
//THEN | |
OCMVerifyAll(objectMock); | |
} |
5. Return-Method
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testReturnMethod_UsingClassMockAndStub { | |
//GIVEN | |
NSString* inputedValue = @"Simulated value"; | |
id objectMock = OCMClassMock([ClassB class]); | |
OCMStub([objectMock executeReturnMethod]).andReturn(inputedValue); | |
//WHEN /* run code under test */ | |
NSString* returnedValue = [objectMock executeReturnMethod]; | |
//THEN | |
XCTAssertEqualObjects(inputedValue, returnedValue); | |
} | |
- (void)testReturnMethod_UsingPartialMockAndStub { | |
//GIVEN | |
NSString* inputedValue = @"Simulated value"; | |
ClassB* object = [[ClassB alloc] init]; | |
//You can comment these codes and run again. | |
id objectMock = OCMPartialMock(object); //Real object | |
OCMStub([objectMock executeReturnMethod]).andReturn(inputedValue); | |
//End comment | |
//WHEN /* run code under test */ | |
NSString* returnedValue = [object executeReturnMethod]; | |
//THEN | |
XCTAssertEqualObjects(inputedValue, returnedValue); | |
} |
6. Block
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testBlockMethod_UsingClassMock { | |
//GIVEN | |
NSString* expectedValue = @"@congpc.ios"; | |
ClassA* object = [[ClassA alloc] init]; | |
//Simulate returned value of a block. You can comment these codes and run again. | |
id objectMock = OCMClassMock([ClassB class]); | |
[[[objectMock stub] andDo:^(NSInvocation *invocation) { | |
void (^successBlock)(NSString* value); | |
//Remember that self and _cmd are arguments 0 and 1. | |
[invocation getArgument:&successBlock atIndex:2]; | |
successBlock(@"@congpc.ios"); | |
}] executeBlockMethod:OCMOCK_ANY]; | |
object->publicClass = objectMock; | |
//End comment | |
//WHEN /* run code under test */ | |
NSString* returnedValue = [object executeReturnMethodAndSubBlock]; | |
//THEN | |
XCTAssertEqualObjects(expectedValue, returnedValue); | |
} |
7. Delegate and DataSource
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testDelegate_UsingClassMockAndExpect_VerifyWithDelay { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id delegateMock = OCMProtocolMock(@protocol(ClassADelegate)); | |
// set an expectation | |
[[delegateMock expect] responsedValue:object value:@"DelegateValue"]; | |
object.delegate = delegateMock; | |
//WHEN | |
[object executeVoidMethodAndDelegate]; | |
//THEN | |
OCMVerifyAllWithDelay(delegateMock, 2); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testDataSourceOfTableView { | |
// create the code under test | |
UITableView *tableView = [[UITableView alloc] init]; | |
// create a protocol mock | |
id mockDataSource = OCMProtocolMock(@protocol(UITableViewDataSource)); | |
// stub a protocol query | |
[OCMStub([mockDataSource numberOfSectionsInTableView:tableView]) andReturnValue:[NSNumber numberWithInteger:4]]; | |
// give the mock to the code under test | |
[tableView setDataSource:mockDataSource]; | |
// execute the code under test | |
NSInteger n = [tableView numberOfSections]; | |
// verify results | |
XCTAssertEqual(4, n, @"should have 4 sections"); | |
} |
8. Notification (Observer)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testNotification_UsingObserverMockAndExpect { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id observerMock = OCMObserverMock(); | |
// set an expectation | |
OCMExpect([observerMock notificationWithName:NOTIFICATION_OF_CLASS | |
object:nil]); | |
// register the mock observer with an NSNotificationCenter | |
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock | |
name:NOTIFICATION_OF_CLASS | |
object:nil]; | |
//WHEN | |
[object executeVoidMethodAndNotification]; | |
//THEN | |
OCMVerifyAll(observerMock); | |
} | |
- (void)testNotification_UsingClassMockAndObserverMockAndStubAndPost { | |
//GIVEN | |
id observerMock = OCMObserverMock(); | |
NSNotification* aNotification = [observerMock notificationWithName:NOTIFICATION_OF_CLASS | |
object:nil]; | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
OCMStub([classMock executeVoidMethod]).andPost(aNotification); | |
object->publicClass = classMock; | |
// register the mock observer with an NSNotificationCenter | |
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock | |
name:NOTIFICATION_OF_CLASS | |
object:nil]; | |
//WHEN | |
[object executeVoidMethodAndSubVoidMethod]; | |
//THEN | |
OCMVerifyAll(classMock); | |
OCMVerifyAll(observerMock); | |
} |
9. Exception
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testException_UsingStrictMock_FailingFast { | |
//GIVEN | |
id strictMock = OCMStrictClassMock([ClassB class]); | |
//WHEN | |
@try { | |
[strictMock executeVoidMethodAndException:@"@congpc.ios"];// this will throw an exception | |
} | |
@catch (NSException *exception) { | |
NSLog(@"%@",exception); | |
} | |
@finally { | |
NSLog(@"Final"); | |
} | |
//THEN | |
OCMVerify([strictMock executeVoidMethodAndException:@"@congpc.ios"]); | |
XCTAssertThrows([strictMock executeVoidMethodAndException:@"@congpc.ios"]);// this will throw an exception | |
} | |
- (void)testException_UsingClassMockAndThrow { | |
//GIVEN | |
//Change NSGenericException to NSRangeException and run again. | |
NSException* anException = [NSException exceptionWithName:NSGenericException reason:@"" userInfo:nil]; | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
OCMStub([classMock executeVoidMethod]).andThrow(anException); | |
object->publicClass = classMock; | |
//WHEN + THEN | |
XCTAssertThrowsSpecificNamed([object executeVoidMethodAndSubVoidMethod], NSException, NSGenericException); | |
} |
10. Advanced topics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testVerifyingInOrder_UsingStrictMock { | |
//GIVEN | |
id strictMock = OCMStrictClassMock([ClassB class]); | |
[strictMock setExpectationOrderMatters:YES]; | |
//WHEN | |
OCMExpect([strictMock executeMethodWithOrder1]); // First | |
OCMExpect([strictMock executeMethodWithOrder2]); // Second | |
//THEN | |
[strictMock executeMethodWithOrder1];//Comment this code and run again. | |
// calling executeMethodWithOrder2 before executeMethodWithOrder1 will cause an exception to be thrown | |
[strictMock executeMethodWithOrder2]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testRejectActions_UsingClassMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
[[classMock reject] executeReturnMethod]; | |
object->publicClass = classMock; | |
//WHEN + THEN | |
[object executeRejectMethod]; | |
} | |
- (void)testRejectActions_UsingPartialMock { | |
//GIVEN | |
ClassB* object = [[ClassB alloc] init]; | |
id classMock = OCMPartialMock(object); | |
[[classMock reject] executeReturnMethod]; | |
//WHEN + THEN | |
[object executeRejectMethod]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testStubActionsAndExpect_UsingClassMock { | |
//GIVEN | |
ClassA* object = [[ClassA alloc] init]; | |
id classMock = OCMClassMock([ClassB class]); | |
OCMExpect([classMock executeReturnMethod]).andReturn(@"@congpc.ios"); | |
object->publicClass = classMock; | |
//WHEN /* run code under test */ | |
[object executeVoidMethodAndReturnMethod]; | |
//THEN | |
OCMVerifyAll(classMock); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testOpenUrl { | |
ViewController *toTest = [[ViewController alloc] init]; | |
NSURL *toOpen = [NSURL URLWithString:@"http://www.google.com"]; | |
// Create a partial mock of UIApplication | |
id mockApplication = [OCMockObject partialMockForObject:[UIApplication sharedApplication]]; | |
// Set an expectation that the UIApplication will be told to open the url | |
[[mockApplication expect] openURL:toOpen]; | |
[toTest launchURL:toOpen]; //Test private method | |
[mockApplication verify]; | |
[mockApplication stopMocking]; | |
} |
Tools: XCode 7, OCMock 3.0
Reference documents:
- OCMock- Engineering
- StackOverflow
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.