I need to be able to determine whether a class method was called or not. How can I do this with OCMock?
-
You may want to look into this: http://stackoverflow.com/questions/1810053/how-to-stub-a-class-method-in-ocmock – zneak Apr 08 '11 at 22:39
-
possible duplicate of [How to mock class method (+)?](http://stackoverflow.com/questions/8427044/how-to-mock-class-method) – Lukas Knuth Mar 17 '13 at 10:49
4 Answers
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.

- 2,933
- 18
- 21
-
Class method are just like instance methods now. Suppose you have a class called _Foo_ which has a class method called _bar_ then you create the mock and write [[[fooMock stub] andReturn:something] bar]. This is described here: http://www.ocmock.org/features/ – Erik Doernenburg Apr 09 '13 at 18:11
-
OK. It appears that when doing this `[MyClass class]` references to the class are mocked, but the result from `[instance class]` is not. – ThomasW Apr 16 '13 at 10:05
-
2Is it possible to do `expect`ations on class methods? `[[mock expect] fooClassMethod:bar]` Does not seem to work. – nacho4d Sep 06 '13 at 09:12
-
I found that expectations are reset after one invocation of the mocked class method. I could not find a way to have the expectation apply across multiple invocations. – fatuhoku Oct 21 '14 at 23:02
-
This is as designed. An `expect` means that you're are expecting the method to be called once. If you want to stub a return value, please use the `stub` method. If you want to express "I want this to be called at least once" use `expect` with a nice mock (now the default in OCMock 3) or `expect` and `stub` (in this order). – Erik Doernenburg Oct 22 '14 at 07:41
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.

- 17,523
- 6
- 79
- 92
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!

- 1
- 1

- 181
- 1
- 2
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

- 3,911
- 2
- 28
- 28