Мне нужно иметь возможность определить, был ли вызван метод класса или нет. Как я могу сделать это с OCMock?
Objective C & OC Mock - Издевательство над методом класса?
Ответы (4)
Начиная с версии OCMock 2.1 это поддерживается из коробки. Теперь вы можете заглушить методы класса так же, как вы заглушаете методы экземпляра.
[MyClass class]
ссылки на класс имитируются, а результат [instance class]
- нет.
- person ThomasW; 16.04.2013
expect
ations для методов класса? [[mock expect] fooClassMethod:bar]
Не работает.
- person nacho4d; 06.09.2013
expect
означает, что вы ожидаете, что метод будет вызван один раз. Если вы хотите заглушить возвращаемое значение, используйте метод stub
. Если вы хотите выразить, что я хочу, чтобы это вызывалось хотя бы один раз, используйте expect
с красивым макетом (теперь по умолчанию в OCMock 3) или expect
и stub
(в этом порядке).
- person Erik Doernenburg; 22.10.2014
Один из подходов состоит в том, чтобы обернуть метод класса в метод вашего собственного класса. Допустим, ваш класс должен вызвать [SomeOtherClass classMethod:someString]
. Вы можете создать метод invokeClassMethod:
в своем классе следующим образом:
-(NSString *)invokeClassMethod:(NSString *)someString {
return [SomeOtherClass classMethod:someString];
}
Затем в своем тесте вы создаете частичный макет и ожидаете invokeClassMethod:
-(void)testSomething {
id partialMock = [OCMockObject partialMockForObject:actual];
[[[partialMock expect] andReturn:@"foo"] invokeClassMethod:@"bar"];
[actual doSomething:@"bar"];
[partialMock verify];
}
Если вы хотите убедиться, что invokeClassMethod
не вызывается, вы можете создать исключение:
-(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"];
}
Исключение приведет к сбою теста, если вызывается invokeClassMethod
.
Как упомянул zneak в своем комментарии к вашему вопросу, посмотрите этот ответ а>,
И из комментариев там проверьте эту блочную реализацию swizzling методов класса.
OCMock
, похоже, напрямую не поддерживает то, что вы хотите сделать, но это решение довольно хорошее!
В качестве альтернативы предположим, что у вас есть класс:
@interface ABCCleverClass : NSObject
+ (id)specialMethod;
@end
и вы хотите издеваться над этим методом класса. Одним из вариантов является создание категории в этом классе, которая определяет и реализует поддержку тестирования. Затем вы можете поменять местами реализацию метода класса в тестируемом классе с вашим макетом из категории.
#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