我使用OCMock测试单例方法。我得到了#34;模拟类中没有这样的方法。" 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;
}
答案 0 :(得分: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
答案 1 :(得分:1)
在上面的描述中,您编写了“单元测试的管理器类别”,但后面的实现不是一个类别,它是Manager
类的实际实现,即代码读取
@implementation Manager
而不是
@implementation Manager(unitTests)
测试代码似乎使用了Manager
的第二个实现,并且该实现没有getOne
方法。所以模仿是抱怨的权利;它看到的Manager
的实现没有方法,因此它不能存根。
我相信你可以通过将实现作为一个类别来修复你的测试。据我所知,可以在类别中覆盖类方法(在您的情况下为sharedManager
),但这样做有点冒险。 Ben Flynn描述的方法更好。