I\'m using OCMock to mock some Core Data objects. Previously, I had the properties implemented with Objective-C 1.0 style explicit accessors:
// -- Old Core
Also responded to your cross-post on the OCMock Forum
Check out http://iamleeg.blogspot.com/2009/09/unit-testing-core-data-driven-apps.html.
Basically he suggests abstracting out your Core Data object's interface to a protocol, and using that protocol instead of the class where you pass instances of your core data object around.
I do this for my core data objects. Then you can use mockForProtocol:
id mockItem = [OCMockObject mockForProtocol:@protocol(MyItemInterface)];
[[[mockItem expect] andReturn:@"fakepath.pdf"] PDFName];
Works great! He also suggests creating a non-core data mock implementation of the interface which just synthesizes the properties:
@implementation MockMyItem
@synthesize PDFName;
@end
...
id <MyItemInterface> myItemStub = [[MockMyItem alloc] init] autorelease];
[myItem setPDFName:@"fakepath.pdf"];
I've used this as well, but I'm not sure it adds anything over the mockForProtocol:/stub: approach, and it's one more thing to maintain.
One of solutions is using a protocol, which is intended to substitute it's original interface, but it could be a bit heavy and leads to significant amount of code you should duplicate.
Personally, I found a way to make it lightweight:
Create a simple category, for instance, inside your unit testing file, just before your unit testing class:
@implementation MyItem(UnitTesing)
- (NSString *)PDFName{return nil;};
@end
Also, you can keep it in separate file, but make sure, that this file is not a part of your production target. That is why I prefer to keep it in the same test file, where I want to use it.
The huge advantage of this method, is that you should not copy methods, that are created by XCode to support relationships. Also you can put to this category only methods you are going to call inside your tests.
There are some caveats, though, for example, you should add another methods inside the category, to support setters, when you are going to check, how correct your code changes the properties of your managed object:
- (void)setPDFName:(NSString *)name{};
The above answer didn't satisfy me, because I didn't like to create a protocol for that. So I found out that there is an easier way to do that. Instead of
[[[mockItem stub] andReturn:@"fakepath.pdf"] PDFName]; // <-- throws exception here
Just write
[[[mockItem stub] andReturn:@"fakepath.pdf"] valueForKey:@"PDFName"];