Mulle kybernetiK presents


OCMock icon

OCMock is an Objective-C implementation of mock objects. If you are unfamiliar with the concept of mock objects please visit mockobjects.com which has more details and discussions about this approach to testing software.

This implementation fully utilises the dynamic nature of Objective-C. It creates mock objects on the fly and uses the trampoline pattern so that you can define expectations and stubs using the same syntax that you use to call methods. No strings, no @selector, just method invocations like this:

[[myMockObject expect] doSomethingWithObject:someObject];

If you have any questions or contributions please join the mailing list by sending an empty message to ocmock-subscribe@mulle-kybernetik.com. Alternatively, you can contact me at Erik Doernenburg <erik@mulle-kybernetik.com>.

19-May-2009

New release (1.42) which combines several contributions, adding support for mock observers of notifications, setters for pass-by-reference arguments, and several improvements to existing features. The default binary release now uses @rpath, which allows for more flexible deployment, and it supports garbage collection.

07-Jul-2008

With this new release (1.29) OCMock supports hamcrest matchers like this:

[[mock expect] doSomething:startsWith(@"foo")]

Note that this dependency is optional. OCMock does not require or link against hamcrest, but if the test suite uses hamcrest matchers and links against hamcrest then OCMock works with the matchers. This release also contains a small bugfix that removes a memory leak in OCMockRecorder.

08-May-2008

New release (1.24) which combines several contributions, adds support for more flexible constraints as well as experimental 64-bit support. The default binary release is now in “embedded” mode.

22-Nov-2007

We now have a mailing list for OCMock. Please send an empty message to ocmock-subscribe@mulle-kybernetik.com to subscribe. The actual mailing list address is ocmock@mulle-kybernetik.com but you must be subscribed to be able to post. (Too much hassle with spam otherwise.)

21-Jun-2007

New release (1.17) which combines several contributions. Added nice mocks, which ignore unexpected invocations, and exceptions meant to cause the test to fail fast are now rethrown in verify.

11-Jun-2006

New release (1.12) which combines several contributions. Added support for stubbing primitive return types, matching nil and struct arguments, and throwing exceptions.

03-Oct-2005

New release (1.10) which has support for mocking protocols. Also added XCode 2.1 compliant project files and moved to built-in OCUnit.

26-Sep-2004

Changed a small but important detail: The MockObject and MockRecorder classes now inherit from NSProxy which carries much less baggage in terms of methods that cannot be mocked because they are defined by the base class.

30-Aug-2004

First public release. I am using the Subversion revision numbers to version the releases, which is why we start with 1.4 and not 1.0 as one could expect.

23-Jul-2004

While working on a new Objective-C project, a Mac OS X monitor for Damage Control, I decide that I've gotten so used to developing test-first and using mock objects that I will bite the bullet and do a simple mock objects implementation in Objective-C. It'll be basic but since Objective-C is so dynamic I probably only need a fraction of the code needed for the Java and .NET versions.

Stable Releases

Version Date File
v1.42 - Source and binary for Mac OS X (10.5 or higher) 19-May-2009 ocmock-1.42.dmg
v1.17 - Source and binary for Mac OS X (10.4 or higher) 21-Jun-2007 ocmock-1.17.tar.gz

Source code

You can fetch the latest version of the code from the Subversion repository at

http://svn.mulle-kybernetik.com/OCMock/trunk

License

Copyright (c) 2004 - 2009 by Mulle Kybernetik. All rights reserved.

Permission to use, copy, modify and distribute this software and its documentation is hereby granted, provided that both the copyright notice and this permission notice appear in all copies of the software, derivative works or modified versions, and any portions thereof, and that both notices appear in supporting documentation, and that credit is given to Mulle Kybernetik in all documents and publicity pertaining to direct or indirect use of this code or its derivatives.

THIS IS EXPERIMENTAL SOFTWARE AND IT IS KNOWN TO HAVE BUGS, SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. THE COPYRIGHT HOLDER ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. THE COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF ANY DERIVATIVE WORK.

Class mocks

id mock = [OCMockObject mockForClass:[SomeClass class]]

Creates a mock object that can be used as if it were an instance of SomeClass.

Expectations and verification

[[mock expect] someMethod:someArgument]

Tells the mock object that someMethod: should be called with an argument that is equal to someArgument. After this setup the functionality under test should be invoked followed by

[mock verify]

The verify method will raise an exception if the expected method has not been invoked.

Stubs

[[[mock stub] andReturn:aValue] someMethod:someArgument]

Tells the mock object that when someMethod: is called with someArgument it should return aValue.

If the method returns a primitive type the return value must be wrapped as follows:

[[[mock stub] andReturnValue:OCMOCK_VALUE(YES)] someMethod:someArgument]

Values can also be returned in pass-by-reference arguments:

[[mock stub] someMethodWithReferenceArgument:[OCMArg setTo:aValue]]

In this case the mock object will set the reference that is passed to the method to aValue, which currently has to be an object.

The mock object can also throw an exception when a method is called:

[[[mock stub] andThrow:anException] someMethod:someArgument]

Note that it is possible to use andReturn:, andThrow:, and setTo: with expect, too. This will then return the given return value and, on verify, ensure that the method has been called.

Argument constraints

[[mock expect] someMethod:[OCMArg any]]

Tells the mock object that someMethod: should be called and it does not matter what the argument is. Pointers require special treatment:

[[mock expect] someMethodWithPointerArgument:[OCMArg anyPointer]]

Other constraints available are:

[[mock expect] someMethod:[OCMArg isNil]]
[[mock expect] someMethod:[OCMArg isNotNil]]
[[mock expect] someMethod:[OCMArg isNotEqual:aValue]]
[[mock expect] someMethod:[OCMArg checkWithSelector:aSelector onObject:anObject]]

The last constraint will, when the mock object receives someMethod:, send aSelector to anObject and if aSelector takes an argument will pass the argument that was passed to someMethod:. The method should return a boolean indicating whether the argument matched the expectation or not.

It is also possible to use Hamcrest matchers like this:

[[mock expect] someMethod:startsWith(@"foo")]

Note that this will only work when the Hamcrest framework is explicitly linked by the unit test bundle.

Nice mocks / failing fast

When a method is called on a mock object that has not been set up with either expect or stub the mock object will raise an exception. This fail-fast mode can be turned off by creating a "nice" mock:

id aMock = [OCMockObject niceMockForClass:[SomeClass class]]

Note that in fail-fast mode, if the exception is ignored, it will be rethrown when verify is called. This makes it possible to ensure that unwanted invocations from notifications etc. can be detected.

Protocol mocks

id aMock = [OCMockObject mockForProtocol:@protocol(SomeProtocol)]

Creates a mock object that can be used as if it were an instance of an object that implements SomeProtocol.

Partial mocks

id aMock = [OCMockObject partialMockForObject:anObject]

Creates a mock object that can be used in the same way as anObject. When a method that is not stubbed is invoked it will be forwarded anObject. When a stubbed method is invoked using a reference to anObject, rather than the mock, it will still be handled by the mock.

Note that currently partial mocks cannot be created for instances of toll-free bridged classes, e.g. NSString.

Observer mocks

id aMock = [OCMockObject observerMock]

Creates a mock object that can be used to observe notifications. The mock must be registered in order to receive notifications:

[notificatonCenter addMockObserver:aMock name:SomeNotification object:nil]

Expectations can then be set up as follows:

[[mock expect] notificationWithName:SomeNotification object:[OCMArg any]]

Note that currently there is no "nice" mode for observer mocks, they will always raise an exception when an unexpected notification is received.

More detail

The test cases in OCMockObjectTests and OCMockObjectHamcrestTests show all uses of OCMock.

Changes.txt contains a chronological list of all changes.

Tutorials/articles for specific topics:

The following is a five minute tutorial contributed by David Phillip Oster <oster@ieee.org>.

Introduction

If you pass a Mock object into a system, Unit tests can use it to mimic the behavior of some other subsystem that isn't the subject of a test.

Create example

mock = [OCMockObject mockForClass:[MyUserManager class]];

or:

mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];

Note, this would mean it returns an autoreleased object.

Usage

- (id)stub
- (id)expect
- (id)andReturn:
- (id)verify

Once you've created a mock object, you need to teach the instance how to behave.

Teach the mock object that it is OK to call it with a specific argument.

[[mock stub] getDatabaseConnection];
[[mock stub] setCurrentUserName: @"foo"];

Teach the mock object that it is OK to call it with any argument.

[[mock stub] setCurrentUserName: OCMOCK_ANY];

Teach the mock to map inputs to outputs:

[[[mock stub] andReturn: @"Jane"] getCurrentUserName];

Teach the mock to require calls of specific methods in specific orders:

[[mock expect] getCurrentUserName];
[[mock expect] logoutCurrentUser];

Then some code that is under test should call the methods on the mock in that order:

-(id)getCurrentUserName
-(id)logoutCurrentUser

Note, the object that uses the mock isn't aware of the fact it deals with a mock, it thinks it has a reference to the real thing.

Then ask it to verify that it saw what it expected to see:

[mock verify]; // @throw's if not valid.

Mock objects @throw's on any invalid call to the mock.