Adding OCMock to your project
- Download a release from the downloads page.
- For iOS development add the static library to your test target. This is described in detail on the iOS page.
- For OS X development simply add
OCMock.frameworkto your test target.
- Alternatively you can use CocoaPods or Carthage.
- Add an import to your unit tests.
Using OCMock – the short version
Creating stubs for instance and class methods
A mock object stands in for a real object. With stubs we can specify what to return when a method is invoked:
// create a mock for the user defaults id userDefaultsMock = OCMClassMock([NSUserDefaults class]); // set it up to return a specific value when stringForKey: is called OCMStub([userDefaultsMock stringForKey:@"MyAppURLKey"]).andReturn(@"http://testurl"); // set it up to return the specified value no matter how the method is invoked OCMStub([userDefaultsMock stringForKey:[OCMArg any]]).andReturn(@"http://testurl");
How do we get the code that we want to test to use the mock? A pattern that is often implemented together with mocks is dependency injection. With cases like
NSUserDefaults we can take an even simpler approach. Our code under test is likely to use the standard shared instance, which is returned by the
standardUserDefaults factory class method. We can simply stub that class method:
// stub a class method to return our mock, and not the standard shared instance OCMStub([userDefaultsMock standardUserDefaults]).andReturn(userDefaultsMock);
Class methods can be stubbed like instance methods. If a class has a class method and an instance method with the same name, OCMock provides a way to specify which one to target. This is described on the reference page.
Verifying behaviour with a mock
Sometimes we not only want to stub a method but we want to ensure (verify) that a given method has been called by the code under test.
// create a mock for the user defaults and make sure it's used id userDefaultsMock = OCMClassMock([NSUserDefaults class]); OCMStub([userDefaultsMock standardUserDefaults]).andReturn(userDefaultsMock); // call the code under test [myController updateUserDefaults]; // verify it has called the expected method OCMVerify([userDefaultsMock setObject:@"http://someurl" forKey:@"MyAppURLKey"]);
When verifying method invocations matchers can be used for the arguments in the same way as described above.
Mocking methods on an existing object: partial mocks
Sometimes we only want to stub or verify a couple of methods, but use the real implementation for all other methods. This is where partial mocks come in:
// create an object and a partial mock for it Foo *myObject = [[Foo alloc] init]; id myObjectMock = OCMPartialMock(myObject); // replace (stub) one method on the object OCMStub([myObjectMock writeToDatabase]).andReturn(@YES); // call the code under test [myController updateDatabase] // verify that the method has been called OCMVerify([[myObjectMock writeToDatabase]);
It is not even necessary to stub a method in order to verify it. If we omit the stub from the code above the actual implementation of
writeToDatabase in the object is used. We can still verify that it has been called.
With the examples on this page we've barely scratched the surface. OCMock has a rich feature set for many different use cases. The following pages provide good next steps to continue learning about OCMock.
- Introduction to mocking with OCMock
- Reference documentation
- Tutorials written by OCMock users
- Mocks aren't stubs, an article by Martin Fowler