10 Years of OCMock
30 Aug 2014
Today is the 10th anniversary of OCMock’s first release. The original code for that release is preserved in the Git repo. Looking back I find it surprising with how little code it all began.
OCMock is an Objective-C implementation of mock objects. It provides
If you are unfamiliar with the concept of mock objects please have a look at the introduction on this site.
The remainder of this page should have everything to get you started. Enjoy!
OCMock.frameworkto your test target.
A mock object stands in for a real object. With stubs we can specify what to return when:
// 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 under 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.
Sometimes we not only want to stub a method but we want to ensure, or 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.
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.