Skip to content

Instantly share code, notes, and snippets.

@kharmabum
Last active October 8, 2022 07:55
Show Gist options
  • Star 95 You must be signed in to star a gist
  • Fork 21 You must be signed in to fork a gist
  • Save kharmabum/51b52c37b6166d897826 to your computer and use it in GitHub Desktop.
Save kharmabum/51b52c37b6166d897826 to your computer and use it in GitHub Desktop.
OCMock cheatsheet
/*----------------------------------------------------*/
#pragma mark - XCTAsserts
/*----------------------------------------------------*/
XCTAssert(expression, format...);
XCTAssertTrue(expression, format...);
XCTAssertFalse(expression, format...);
XCTAssertEqual(expression1, expression2, format...);
XCTAssertNotEqual(expression1, expression2, format...);
XCTAssertNil(expression, format...);
XCTAssertNotNil(expression, format...);
XCTFail(format...);
/*----------------------------------------------------*/
#pragma mark - Expecta matchers
/*----------------------------------------------------*/
expect(x).to.equal(y);
expect(x).to.beIdenticalTo(y);
expect(x).to.beNil();
expect(x).to.beTruthy();
expect(x).to.beFalsy();
expect(x).to.contain(y);
expect(x).to.beSupersetOf(y);
expect(x).to.haveCountOf(y);
expect(x).to.beEmpty();
expect(x).to.beInstanceOf([Foo class]);
expect(x).to.beKindOf([Foo class]);
expect([Foo class]).to.beSubclassOf([Bar class]);
expect(x).to.beLessThan(y);
expect(x).to.beLessThanOrEqualTo(y);
expect(x).to.beGreaterThan(y);
expect(x).to.beGreaterThanOrEqualTo(y);
expect(x).to.beInTheRangeOf(y,z);
expect(x).to.beCloseTo(y);
expect(x).to.beCloseToWithin(y, z);
expect(^{ /* code */ }).to.raise(@"ExceptionName");
expect(^{ /* code */ }).to.raiseAny();
expect(x).to.conformTo(y);
expect(x).to.respondTo(y);
expect(^{ /* code */ }).to.notify(@"NotificationName");
expect(^{ /* code */ }).to.notify(notification);
expect(x).to.beginWith(y);
expect(x).to.endWith(y);
// inverting matchers
expect(x).notTo.equal(y);
expect(x).toNot.equal(y);
// asynchronous testing
[Expecta setAsynchronousTestTimeout:x] // default is 1 sec
expect(x).will.beNil();
expect(x).willNot.beNil();
expect(x).after(3).to.beNil();
expect(x).after(2.5).notTo.equal(42);
/*----------------------------------------------------*/
#pragma mark - OCMock v3.x
/*----------------------------------------------------*/
// default mock creation
id classMock = OCMClassMock([SomeClass class]); // default is nice
id protocolMock = OCMProtocolMock(@protocol(SomeProtocol)); // default is nice
// strict mock creation
id classMock = OCMStrictClassMock([SomeClass class]);
id protocolMock = OCMStrictProtocolMock(@protocol(SomeProtocol));
//Partial mocks alter the class of the mocked object, though. (In fact, they create a subclass and switch the class of the mocked object to that subclass.)
// This means that calls using a reference to the real object, even including self in methods where the object calls itself, are also affected by stubs and expectations.
id partialMock = OCMPartialMock(anObject);
OCMStub([mock someMethod]).andReturn(anObject);
OCMStub([mock aMethodReturningABoolean]).andReturn(YES);
OCMStub([mock someMethod]).andThrow(anException);
OCMStub([mock someMethod]).andPost(aNotification);
OCMStub([mock someMethod]).andPost(aNotification).andReturn(aValue);
OCMStub([mock someMethod]).andForwardToRealObject(); // only useful when chaining actions or when using expectations.
OCMStub([mock someMethod]).andDo(nil); // supress behavior. only useful with partial mocks or when mocking class methods
// delegatign to another method (aka swizzling)
// method signatures must match
// Arguments will be passed, and the return value of the replacement method is returned from the stubbed method.
// It is common to implement the replacement method in the test case itself.
OCMStub([mock someMethod]).andCall(anotherObject, @selector(aDifferentMethod));
OCMStub([partialMock someMethod]).andCall(anotherObject, @selector(aDifferentMethod)); // per instance basis
// delegating to a block
OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation)
{ /* block that handles the method invocation */ });
// pas by reference arguments
OCMStub([mock someMethodWithReferenceArgument:[OCMArg setTo:anObject]]);
OCMStub([mock someMethodWithReferenceArgument:[OCMArg setToValue:OCMOCK_VALUE((int){aValue})]]);
// Verifying interactions
//
// There is no need to insure that a reference to the mock is used, calls can be made using references to the real object.
// If the method has not been invoked an error is reported.
OCMVerify([anObject someMethod]); // OR
OCMVerify([mock someMethod]);
// Strict mocks and expectations
//
// If an expected method has not been invoked, or has not been invoked with the right arguments, then an error is reported
id classMock = OCMClassMock([SomeClass class]);
OCMExpect([classMock someMethodWithArgument:[OCMArg isNotNil]]);
OCMExpect([classMock someMethod]).andReturn(@"a string for testing");
/* run code under test, which is assumed to call someMethod */
OCMVerifyAll(classMock);
OCMVerifyAllWithDelay(mock, aDelay);
// Expectation order
[mock setExpectationOrderMatters:YES];
OCMExpect([mock someMethod]);
OCMExpect([mock anotherMethod]);
/* calling anotherMethod before someMethod will cause an exception to be thrown */
[mock anotherMethod];
// Nice mocks and rejections
//
// Regular mock objects simply return the default value for the return type for
// methods that haven't been set up with stub/expect but can be configured on
// a per-method basis to fail fast:
id mock = OCMClassMock([SomeClass class]);
[[mock reject] someMethod];
OCMVerifyAll(mock);
// Argument constraints
OCMStub([mock someMethodWithAnArgument:[OCMArg any]]) ;
OCMStub([mock someMethodWithPointerArgument:[OCMArg anyPointer]]);
OCMStub([mock someMethodWithSelectorArgument:[OCMArg anySelector]]);
[[[mock stub] ignoringNonObjectArgs] someMethodWithIntArgument:0]; // to ignore args that are not objects, pointers, selectors
// Matching arguments
OCMStub([mock someMethod:aValue]);
OCMStub([mock someMethod:[OCMArg isNil]]);
OCMStub([mock someMethod:[OCMArg isNotNil]]);
OCMStub([mock someMethod:[OCMArg isNotEqual:aValue]]);
OCMStub([mock someMethod:[OCMArg isKindOfClass:[SomeClass class]]]);
OCMStub([mock someMethod:[OCMArg checkWithSelector:aSelector onObject:anObject]]);
OCMStub([mock someMethod:[OCMArg checkWithBlock:^BOOL(id value) { /* return YES if value is ok */ }]]);
// Stubbing class methods is generally done by the same means.
// in the event an instance and class method share the same name...
id classMock = OCMClassMock([SomeClass class]);
OCMStub(ClassMethod([classMock ambiguousMethod])).andReturn(@"Test string");
// restores a class - removes stub implementations
// This is only necessary if the original state must be restored before the end of the test.
// The mock automatically calls stopMocking during its own deallocation.
[classMock stopMocking];
// observer mocks - strict by default
id observerMock = OCMObserverMock();
[notificatonCenter addMockObserver:observerMock name:SomeNotification object:nil];
[[observerMock expect] notificationWithName:SomeNotification object:[OCMArg any]];
OCMVerifyAll(observerMock);
// Notes:
// * Only one mock at a time can stub class methods on a given class otherwise behavior is undefined
// * If the mock object that added a stubbed class method is not deallocated then the stubbed method will persist, even across tests
// * Always set up `stub` after `expect` (or just do or the other)
// * It is not possible to create partial mocks for instances of toll-free bridged class, e.g. NSString, or for objects represented with tagged pointers, e.g. NSDate on some architectures.
// * It is not possible to mock certain core runtime methods including class, methodSignatureForSelector:, and forwardInvocation:
// * It is not possible to stub or verify class methods on NSString.
// * It is not possible use verify-after-running with methods implemented in NSObject or a category on it. It is possible to use verify-after-running when the method is overriden in a subclass.
// * It is not possible use verify-after-running with private methods in core Apple classes (all methods with an underscore prefix and/or suffix in a class with either NS or UI as prefix).
// * It is currently not possible to verify a method with a delay. This is currently only possible using the expect-run-verify approach
/*----------------------------------------------------*/
#pragma mark - OCMock v2.x
/*----------------------------------------------------*/
// Making mocks
//
// Factory Method Description
// +mockForClass: Create a mock based on the given class
// +mockForProtocol: Create a mock based on the given protocol
// +niceMockForClass: Create a "nice" mock based on the given class
// +niceMockForProtocol: Create a "nice" mock based on the given protocol
// +partialMockForObject: Create a mock based on the given object
// +observerMock: Create a notification observer (more on this later)
// Return values
//
// Method Explanation
// -andReturn: Return the given object
// -andReturnValue: Return a non-object value (wrapped in a NSValue)
// -andThrow: Throw the given exception
// -andPost: Post the given notification
// -andCall:onObject: Call the selector on the given object
// -andDo: Invoke the given block (only on OS X 10.6 or iOS 4)
// Args
//
// OCMArg method Description
// +any Any argument is accepted.
// +anyPointer Accepts any pointer
// +isNil The given argument must be nil
// +isNotNil The given argument must not be nil
// +isNotEqual: Given argument is not object-equivalent with expectation
// +checkWithSelector:onObject: Check the argument with the given action/target pair
// +checkWithBlock: Check the argument with the given block (OS X 10.6 or iOS 4)
id mockThing = [OCMock mockForClass[Thing class]];
Thing *someThing = [Thing alloc] init];
id aMock = [OCMockObject partialMockForObject:someThing]
/*----------------------------------------------------*/
#pragma mark - Callbacks
/*----------------------------------------------------*/
// - (void)downloadWeatherDataForZip:(NSString *)zip
// callback:(void (^)(NSDictionary *response))callback;
- (void)testCallbackHandling
{
Thing *someThing = [Thing alloc] init];
id aMock = [OCMockObject partialMockForObject:someThing]
[[[aMock stub] andDo:^(NSInvocation *invoke) {
//2. declare a block with same signature
void (^weatherStubResponse)(NSDictionary *dict);
//3. link argument 3 with with our block callback
[invoke getArgument:&weatherStubResponse atIndex:3];
//4. invoke block with pre-defined input
NSDictionary *testResponse = @{@"high": 43 , @"low": 12};
weatherStubResponse(groupMemberMock);
}] downloadWeatherDataForZip@"80304" callback:[OCMArg any] ];
}
/*----------------------------------------------------*/
#pragma mark - Singleton testing
/*----------------------------------------------------*/
- (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];
// Even though the method is invoked on the 'real' singleton ref and not the mock, the mock still handles it
// and can be used to verify
[toTest launchURL:toOpen];
[mockApplication verify];
[mockApplication stopMocking];
}
/*----------------------------------------------------*/
#pragma mark - Exposing private data/methods w/ category
/*----------------------------------------------------*/
#import "SomeObject.h"
// Definition of the category Test on the class SomeObject
@interface SomeObject (Test)
- (void)aPrivateMethod;
@end
@interface SomeObjectTests : XCTestCase
@property (nonatomic, strong) SomeObject *toTest;
@end
@implementation SomeObjectTests
- (void)setUp
{
[super setUp];
self.toTest = [[SomeObject alloc] init];
}
- (void)testPrivateMethod
{
[self.toTest aPrivateMethod];
}
@end
/*----------------------------------------------------*/
#pragma mark - Mocking protocol
/*----------------------------------------------------*/
- (void)testInit {
id mockService = [OCMockObject mockForProtocol:@protocol(AVQuoteService)];
[[mockService expect] initiateConnection];
AVStockPortfolio *portfolio = [[AVStockPortfolio alloc] initWithService:mockService];
[mockService verify];
}
/*----------------------------------------------------*/
#pragma mark - Verify notification observed
/*----------------------------------------------------*/
- (void)testSellSharesInStock {
id mock = [OCMockObject observerMock];
// OCMock adds a custom methods to NSNotificationCenter via a category
[[NSNotificationCenter defaultCenter] addMockObserver:mock
name:AVStockSoldNotification
object:nil];
[[mock expect] notificationWithName:AVStockSoldNotification object:[OCMArg any]];
AVPortfolio *portfolio = [self createPortfolio]; // made-up factory method
[portfolio sellShares:100 inStock:@"AAPL"];
[mock verify];
}
/*----------------------------------------------------*/
#pragma mark - Post notifications with stubs
/*----------------------------------------------------*/
- (void)testNotification
{
NSNotification *notfication = [NSNotification notificationWithName:@"foo" object:nil];
[[[mock expect] andPost:notfication] andReturn:@"FOOBAR"] doSomethingMagical];
}
/*----------------------------------------------------*/
#pragma mark - Validate args, general mucking around
/*----------------------------------------------------*/
- (void)testSellSharesInStock {
id quoteService = [[OCMockObject] mockForProtocol:@protocol(AVQuoteService)];
[[[quoteService expect] andDo:^(NSInvocation *invocation) {
// validate arguments, set return value on the invocation object
}] priceForStock:@"AAPL"];
AVStockPortfolio *portfolio = [[AVStockPortfolio alloc] initWithService:quoteService];
[portfolio sellShares:100 inStock:@"AAPL"];
// other validations and assertions
[quoteService verify];
}
@SanCHEESE
Copy link

Thank you! Very useful

@aitemr
Copy link

aitemr commented Jul 29, 2019

Thank you 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment