Objective C & OC Mock - Издевательство над методом класса?

Мне нужно иметь возможность определить, был ли вызван метод класса или нет. Как я могу сделать это с OCMock?


person aryaxt    schedule 08.04.2011    source источник
comment
Вы можете изучить это: stackoverflow.com/questions/1810053/   -  person zneak    schedule 09.04.2011
comment
возможный дубликат Как имитировать метод класса (+)?   -  person Lukas Knuth    schedule 17.03.2013


Ответы (4)


Начиная с версии OCMock 2.1 это поддерживается из коробки. Теперь вы можете заглушить методы класса так же, как вы заглушаете методы экземпляра.

person Erik Doernenburg    schedule 16.03.2013
comment
Метод класса теперь похож на методы экземпляра. Предположим, у вас есть класс с именем Foo, у которого есть метод класса с именем bar, затем вы создаете макет и пишете [[[fooMock stub] andReturn:something] bar]. Это описано здесь: ocmock.org/features - person Erik Doernenburg; 09.04.2013
comment
OK. Похоже, что при этом [MyClass class] ссылки на класс имитируются, а результат [instance class] - нет. - person ThomasW; 16.04.2013
comment
Можно ли делать expectations для методов класса? [[mock expect] fooClassMethod:bar] Не работает. - person nacho4d; 06.09.2013
comment
Я обнаружил, что ожидания сбрасываются после одного вызова метода имитируемого класса. Я не смог найти способ применить ожидание к нескольким вызовам. - person fatuhoku; 22.10.2014
comment
Это так, как задумано. 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.

person Christopher Pickslay    schedule 11.04.2011

Как упомянул zneak в своем комментарии к вашему вопросу, посмотрите этот ответ ,

И из комментариев там проверьте эту блочную реализацию swizzling методов класса.

OCMock, похоже, напрямую не поддерживает то, что вы хотите сделать, но это решение довольно хорошее!

person Nathaniel Heinrichs    schedule 02.07.2012

В качестве альтернативы предположим, что у вас есть класс:

@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
person Daniel Thorpe    schedule 06.10.2013