If you ever find yourself shying away from class methods in your Objective-C designs on the grounds that they reduce the testability of your code, think again:
- (void)testDateSwizzling
{
Method originalDate = class_getClassMethod([NSDate class], @selector(date));
Method mockDate = class_getInstanceMethod([self class], @selector(mockDate));
method_exchangeImplementations(originalDate, mockDate);
STAssertEquals([NSDate date], [NSDate distantPast], @"Should have mocked method");
method_exchangeImplementations(mockDate, originalDate);
}
- (NSDate *)mockDate
{
return [NSDate distantPast];
}
This allows you to substitute your own implementation for a class method, using the magic of Objective-C’s runtime library. I’m going to have a look at how this could be packaged up for OCMock to make the syntax a little nicer, but I’m already using it wherever it simplifies my APIs (NSDates in particular) and wherever I can’t or don’t want to refactor third-party libraries.
Thom.
You rule. Thankyou so much for pointing this out. As a newbie to Cocoa trying to get his app properly tested I’d hit a roadblock in trying to figure out how to properly mock out the date class method of NSDate.
I had no idea that this runtime library even existed. Thank goodness I Googled before trying to wangle my own half baked solution involving rewriting half my application. And this will simplify loads of my existing code. I’ve no idea why I didn’t know of this sooner. *slaps own forehead*.
Once again, you rule. Thanks for putting this out there for newbies like me.
John