Ошибка модульного теста OCMock

Я использую OCMock для тестирования одноэлементных методов. Я получаю: «В издеваемом классе такого метода не существует». ошибка для метода testSingleton и бесконечный цикл (скриншот, вращающийся индикатор) для метода testSingletonWithBlock

РЕДАКТИРОВАТЬ: скачать образец проекта здесь

https://drive.google.com/file/d/0B-iP0P7UfFj0LVFpWWpPb3RDZFU/edit?usp=sharing

введите здесь описание изображения

Вот моя реализация

управляющий делами:

@implementation Manager
+ (Manager *)sharedManager {
    static Manager *instance;
    dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        instance = [Manager new];
    });
    return instance;
}
- (int)getOne {
    return 1;
}
- (void)success:(BOOL)success completion:(void(^)(void))completion failure:(void(^)(void))failure {
    success ? completion() : failure();
}

просмотр контроллера:

- (void)manager_printOne {
    int num = [[Manager sharedManager] getOne];
    NSLog(@"number is: %d", num);
}

- (void)manager_success:(BOOL)success completion:(void(^)(void))completion failure:(void(^)(void))failure {

    [[Manager sharedManager] success:success completion:completion failure:failure];

}

контроллер тестового представления:

@interface coreDataTestTests : XCTestCase

@property (nonatomic, strong) id mockManager;

@property (nonatomic, strong) ViewController *viewController;

@end

@implementation coreDataTestTests

- (void)setUp
{
    [super setUp];

    self.viewController = [ViewController new];

    //for singleton
    self.mockManager = [Manager createNiceMockManager];
}

- (void)tearDown
{
    [super tearDown];

    self.viewController = nil;


    //Note: singleton need both, retain counts = 2
    self.mockManager = nil;
    [Manager releaseInstance];

}



- (void)testSingleton {

    NSLog(@"testSingleton");
    OCMStub([self.mockManager getOne]).andReturn(2);
    [self.viewController manager_printOne];

}



- (void)testSingletonWithBlock {

    NSLog(@"testSingletonWithBlock");

    [[[[self.mockHelper stub] ignoringNonObjectArgs] andDo:^(NSInvocation *invocation) {

        void(^block)(void);

        [invocation getArgument:&block atIndex:3];
        block();

    }] success:0 completion:[OCMArg any] failure:[OCMArg any]];


    [self.viewController manager_success:NO completion:^{
        NSLog(@"completion");
    } failure:^{
        NSLog(@"failure");
    }];



}




@end

Категория менеджера для модульного теста:

static Manager *mockManager = nil;

@implementation Manager

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

+ (Manager *)sharedManager {
    if (mockManager) {
        return mockManager;
    }
    return invokeSupersequentNoParameters();
}



#pragma clang diagnostic pop

+(id)createMockManager {
    mockManager = [OCMockObject mockForClass:[Manager class]];
    return mockManager;
}

+(id)createNiceMockManager {
    mockManager = [OCMockObject niceMockForClass:[Manager class]];
    return mockManager;
}

+(void)releaseInstance {
    mockManager = nil;
}

person OMGPOP    schedule 31.08.2014    source источник


Ответы (2)


Вместо того, чтобы создавать категорию, вы можете просто заглушить sharedManager и вернуть хороший макет.

- (void)setUp
{
    [super setUp];

    self.viewController = [ViewController new];

    //for singleton
    id classMockManager = OCClassMock([Manager class]);
    OCMStub([classMockManager sharedManager]).andReturn(classMockManager);
    self.mockManager = classMockManager;
}

У меня нет среды, чтобы проверить это прямо сейчас, но эта стратегия должна работать. Обратите внимание, что это синтаксис OCMock3. См. http://ocmock.org/reference/#mocking-class-methods.

person Ben Flynn    schedule 31.08.2014
comment
Это сработало! Можете ли вы объяснить, почему мой оригинальный подход терпит неудачу? Я добавил ссылку для скачивания в пример проекта - person OMGPOP; 31.08.2014
comment
Прохладный. Я не уверен, почему ваш подход не сработал - у меня нет времени глубоко погрузиться в него прямо сейчас, но, возможно, в будущем! - person Ben Flynn; 01.09.2014

В вашем описании выше вы пишете «категория менеджера для модульного теста», но следующая реализация не является категорией, это фактическая реализация класса Manager, т.е. код читает

@implementation Manager

и не

@implementation Manager(unitTests)

Похоже, что в тестовом коде используется вторая реализация Manager, и в этой реализации нет метода getOne. Так что насмешка имеет право жаловаться; реализация Manager, которую он видит, не имеет метода и, следовательно, не может его заглушить.

Я считаю, что вы можете исправить свой тест, сделав реализацию категорией. Насколько я знаю, можно переопределить метод класса (в вашем случае sharedManager) в категории, но делать это немного рискованно. Подход, описанный Беном Флинном, лучше.

person Erik Doernenburg    schedule 02.09.2014