Reputation: 77596
I need to be able to determine whether a class method was called or not. How can I do this with OCMock?
Upvotes: 4
Views: 6746
Reputation: 3931
Alternatively, lets assume that you have the class:
@interface ABCCleverClass : NSObject
+ (id)specialMethod;
@end
and you want to mock this class method. One option is to create a category on this class which defines and implements testing support. Then, you can swap the implementation of the class method in the class under test with your mock one from the category.
#import <objc/runtime.h>
@interface ABCCleverClass (TestSupport)
+ (id)mockSpecialMethod;
@end
@implementation ABCCleverClass (TestSupport)
+ (void)load {
Method original = class_getClassMethod([ABCCleverClass class], @selector(specialMethod));
Method mocked = class_getClassMethod([ABCCleverClass class], @selector(mockSpecialMethod));
method_exchangeImplementations(original, mocked);
}
+ (id)mockSpecialMethod {
// Perform mock method. You may need to add more class methods
// in order to configure this.
}
@end
Upvotes: 1
Reputation: 3014
Starting with OCMock release 2.1 this is supported out of the box. You can now stub class methods in the same way as you stub instance methods.
Upvotes: 6
Reputation: 181
As zneak mentioned in their comment to your question, have a look at this answer,
And from the comments there, checkout this block-based implementation of class method swizzling.
OCMock
doesnt seem to directly support what you want to do, but this solution is quite nice!
Upvotes: 2
Reputation: 17762
One approach is to wrap the class method in a method on your own class. So let's say your class has to call [SomeOtherClass classMethod:someString]
. You could create a method invokeClassMethod:
on your class like this:
-(NSString *)invokeClassMethod:(NSString *)someString {
return [SomeOtherClass classMethod:someString];
}
Then in your test, you create a partial mock and expect invokeClassMethod:
-(void)testSomething {
id partialMock = [OCMockObject partialMockForObject:actual];
[[[partialMock expect] andReturn:@"foo"] invokeClassMethod:@"bar"];
[actual doSomething:@"bar"];
[partialMock verify];
}
If you want to verify that invokeClassMethod
isn't called, you can throw an exception:
-(void)testSomethingElse {
id partialMock = [OCMockObject partialMockForObject:actual];
[[[partialMock stub] andThrow:[NSException exceptionWithName:@"foo" reason:@"Should not have called invokeClassMethod:" userInfo:nil] invokeClassMethod:OCMOCK_ANY];
[actual doSomething:@"bar"];
}
The excpetion will cause the test to fail if invokeClassMethod
is called.
Upvotes: 3