Skip to content

Instantly share code, notes, and snippets.

@oks
Forked from kharmabum/ocmock-cheatsheet.m
Last active May 11, 2023 14:07
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save oks/a32688f31b092388b3e8 to your computer and use it in GitHub Desktop.
Save oks/a32688f31b092388b3e8 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 - Quick
expect(x)).to(equal(y));
expectAction(^{ [exception raise]; }).to(raiseException()); // no return value expectation
// Passes if actual is equivalent to expected:
expect(actual).to(equal(expected))
// Passes if actual is not equivalent to expected:
expect(actual).toNot(equal(expected))
// Passes if actual has the same pointer address as expected:
expect(actual).to(beIdenticalTo(expected));
// Passes if actual does not have the same pointer address as expected:
expect(actual).toNot(beIdenticalTo(expected));
expect(actual).to(beLessThan(expected));
expect(actual).to(beLessThanOrEqualTo(expected));
expect(actual).to(beGreaterThan(expected));
expect(actual).to(beGreaterThanOrEqualTo(expected));
expect(actual).to(beCloseTo(expected).within(delta)); // expect(@(10.01)).to(beCloseTo(@10).within(0.1));
//beAnInstanceOf uses the -[NSObject isMemberOfClass:] method to test membership. beAKindOf uses -[NSObject isKindOfClass:].
// Passes if instance is an instance of aClass:
expect(instance).to(beAnInstanceOf(aClass));
// Passes if instance is an instance of aClass or any of its subclasses:
expect(instance).to(beAKindOf(aClass));
// Passes if actual is not nil, true, or an object with a boolean value of true:
expect(actual).to(beTruthy());
// Passes if actual is only true (not nil or an object conforming to BooleanType true):
expect(actual).to(beTrue());
// Passes if actual is nil, false, or an object with a boolean value of false:
expect(actual).to(beFalsy());
// Passes if actual is only false (not nil or an object conforming to BooleanType false):
expect(actual).to(beFalse());
// Passes if actual is nil:
expect(actual).to(beNil());
// Passes if actual, when evaluated, raises an exception:
expect(actual).to(raiseException())
// Passes if actual raises an exception with the given name
expect(actual).to(raiseException().named(name))
// Passes if actual raises an exception with the given name and reason:
expect(actual).to(raiseException().named(name).reason(reason))
// Passes if actual raises an exception and it passes expectations in the block
// (in this case, if name begins with 'a r')
expect(actual).to(raiseException().satisfyingBlock(^(NSException *exception) {
expect(exception.name).to(beginWith(@"a r"));
}));
// Passes if expected is a member of actual:
expect(actual).to(contain(expected)); //expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"dolphin"));
// Passes if actual is an empty collection (it contains no elements):
expect(actual).to(beEmpty());
// Passes if the elements in expected appear at the beginning of actual:
expect(actual).to(beginWith(expected));
// Passes if the the elements in expected come at the end of actual:
expect(actual).to(endWith(expected));
// Passes if actual contains substring expected:
expect(actual).to(contain(expected));
// Passes if actual begins with substring:
expect(actual).to(beginWith(expected));
// Passes if actual ends with substring:
expect(actual).to(endWith(expected));
// Passes if actual is an empty string, "":
expect(actual).to(beEmpty());
// Passes if actual matches the regular expression defined in expected:
expect(actual).to(match(expected))
expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5)));
// passes if actual collection's count is equal to expected
expect(actual).to(haveCount(expected))
// passes if actual collection's count is not equal to expected
expect(actual).notTo(haveCount(expected))
// passes if actual is either less than 10 or greater than 20
expect(actual).to(satisfyAnyOf(beLessThan(@10), beGreaterThan(@20)))
// can include any number of matchers -- the following will pass
// **be careful** -- too many matchers can be the sign of an unfocused test
expect(@6).to(satisfyAnyOf(equal(@2), equal(@3), equal(@4), equal(@5), equal(@6), equal(@7)))
waitUntil(^(void (^done)(void)){
// do some stuff that takes a while...
[NSThread sleepForTimeInterval:0.5];
done();
});
waitUntilTimeout(10, ^(void (^done)(void)){
// do some stuff that takes a while...
[NSThread sleepForTimeInterval:1];
done();
});
//Quick
beforeSuite(^{
[OceanDatabase createDatabase:@"test.db"];
[OceanDatabase connectToDatabase:@"test.db"];
});
afterSuite(^{
[OceanDatabase teardownDatabase:@"test.db"];
});
beforeEachWithMetadata(^(ExampleMetadata *exampleMetadata){
NSLog(@"Example number %l is about to be run.", (long)exampleMetadata.exampleIndex);
});
afterEachWithMetadata(^(ExampleMetadata *exampleMetadata){
NSLog(@"Example number %l has run.", (long)exampleMetadata.exampleIndex);
});
describe(@"a dolphin", ^{
__block Dolphin *dolphin = nil;
beforeEach(^{ dolphin = [Dolphin new]; });
describe(@"its click", ^{
context(@"when the dolphin is not near anything interesting", ^{
it(@"is only emitted once", ^{
expect(@([[dolphin click] count])).to(equal(@1));
});
});
context(@"when the dolphin is near something interesting", ^{
beforeEach(^{
[[Jamaica dolphinCove] add:[SunkenShip new]];
[[Jamaica dolphinCove] add:dolphin];
});
it(@"is emitted three times", ^{
expect(@([[dolphin click] count])).to(equal(@3));
});
});
});
});
QuickConfigurationBegin(EdibleSharedExamplesConfiguration)
+ (void)configure:(Configuration *configuration) {
sharedExamples(@"something edible", ^(QCKDSLSharedExampleContext exampleContext) {
it(@"makes dolphins happy") {
Dolphin *dolphin = [[Dolphin alloc] init];
dolphin.happy = NO;
id<Edible> edible = exampleContext()[@"edible"];
[dolphin eat:edible];
expect(dolphin.isHappy).to(beTruthy())
}
});
}
QuickConfigurationEnd
QuickSpecBegin(MackerelSpec)
__block Mackerel *mackerel = nil;
beforeEach(^{
mackerel = [[Mackerel alloc] init];
});
itBehavesLike(@"someting edible", ^{ return @{ @"edible": mackerel }; });
QuickSpecEnd
QuickSpecBegin(CodSpec)
__block Mackerel *cod = nil;
beforeEach(^{
cod = [[Cod alloc] init];
});
itBehavesLike(@"someting edible", ^{ return @{ @"edible": cod }; });
QuickSpecEnd
/*----------------------------------------------------*/
#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];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment