Ios OCMock单元测试错误

Ios OCMock单元测试错误,ios,objective-c,unit-testing,ocmock,xctest,Ios,Objective C,Unit Testing,Ocmock,Xctest,我使用OCMock测试单例方法。我发现mock类中不存在这样的方法。testSingleton方法和无限循环出错屏幕截图,testSingleton WithBlock方法的旋转指示器 编辑: 在此下载示例项目 这是我的实现 经理: @implementation Manager + (Manager *)sharedManager { static Manager *instance; dispatch_once_t predicate; dispatch_once(&

我使用OCMock测试单例方法。我发现mock类中不存在这样的方法。testSingleton方法和无限循环出错屏幕截图,testSingleton WithBlock方法的旋转指示器

编辑: 在此下载示例项目

这是我的实现

经理:

@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
测试视图控制器:

- (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;
}

您可以只存根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语法。请参见上面的描述,您为单元测试编写了manager类别,但下面的实现不是类别,而是manager类的实际实现,即代码读取

@implementation Manager
而不是

@implementation Manager(unitTests)
测试代码似乎使用了Manager的第二个实现,而该实现没有getOne方法。因此,嘲笑者抱怨是正确的;它看到的管理器的实现没有该方法,因此它不能存根它


我相信您可以通过将实现作为一个类别来修复测试。据我所知,在您的案例中,可以在类别中重写类方法sharedManager,但这样做有点冒险。Ben Flynn描述的方法更好。

它奏效了!你能解释一下为什么我最初的方法失败了吗?我已经在示例projectCool中添加了一个下载链接。我不知道为什么你的方法不起作用-我现在没有时间深入研究它,但也许在将来!