2014-08-31 178 views
2

我使用OCMock来测试单例方法。我得到“模拟班级中不存在这样的方法。”误差为testSingletonWithBlock方法OCMock单元测试错误

编辑testSingleton方法和无限循环(截图,纺纱指标): 下载样品这儿项目

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

enter image description here

这是我实现

经理:

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

回答

3

而不是创建一个类别,你可以只存根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

+0

它的工作!你能解释为什么我原来的方法失败了吗?我已经添加了一个下载链接到示例项目 – OMGPOP 2014-08-31 02:31:32

+0

Cool。我不确定你的方法为什么不起作用 - 我现在没有时间深入研究它,但也许在将来! – 2014-09-01 01:43:19

1

在你的描述你上面写的“经理类的单元测试”,但其后的执行是不是一个类别,它是一个真正实现Manager类,即代码读取

@implementation Manager 

而不是

@implementation Manager(unitTests) 

看来,测试代码使用第二个实施Manager和执行不具有getOne方法。所以模拟是正确的抱怨;它看到的Manager的实现没有方法,因此它不能存根。

我相信你可以通过使实现成为一个类来修复你的测试。据我所知,可以在类别中覆盖类方法(在你的情况下为sharedManager),但这样做有点冒险。 Ben Flynn描述的方法更好。