|
|
|
|
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];
A small tutorial can be found further down on this page and I have recently written a tutorial that shows how to use OCMock to test Cocoa controllers. The test cases in OCMockObjectTests and OCMockObjectHamcrestTests show all uses of OCMock, and Changes.txt contains a chronological list of all changes.
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>.
News
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.
Tutorial
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.
Further reading
OCMock also has lots of tests, which means that you can get a good idea of all features by looking at the OCMockObjectTests.
License
Copyright (c) 2004 - 2008 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.
|