我正在学习使用OCMocks进行单元测试,并且我了解基础知识。但是,我不确定如何模拟对类方法的调用。
我想:
[[UIDevice currentDevice] userInterfaceIdiom]
为我的测试用例返回不同(但有效)的界面惯用语。
id mock = [OCMockObject mockForClass:[UIDevice class]];
// Would I use a mock or a stub to have UIDevice mock return
// currentDevice and then from it, return userInterfaceIdiom
答案 0 :(得分:3)
这是一个简单的解决方案:
OCMockObject* _deviceMock = OCMPartialMock([UIDevice currentDevice]);
[[[_deviceMock stub] andReturnValue:@(UIUserInterfaceIdiomPad)] userInterfaceIdiom];
确保行为中的代码使用此检查
[UIDevice currentDevice].userInterfaceIdiom
宏的INSTEAD
UI_USER_INTERFACE_IDIOM()
答案 1 :(得分:2)
嘲弄单身人士很棘手。你可以用一些运行时魔术来做到这一点。可以在Matt Gallagher's invokeSupersequent macro的帮助下完成。基本上,只有在设置了模拟时,才会在测试用例中添加一个类别,该类别会覆盖currentDevice
以返回模拟。这是设置:
#import "NSObject+SupersequentImplementation.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
@implementation UIDevice (UnitTests)
+(id)currentDevice {
if ([BaseTestCase mockDevice]) {
return [BaseTestCase mockDevice];
}
return invokeSupersequentNoArgs();
}
@end
#pragma clang diagnostic pop
static id mockDevice = nil;
+(id)mockDevice {
return mockDevice;
}
+(id)createMockDevice {
mockDevice = [OCMockObject mockForClass:[UIDevice class]];
return mockDevice;
}
+(id)createNiceMockDevice {
mockDevice = [OCMockObject niceMockForClass:[UIDevice class]];
return mockDevice;
}
-(void)tearDown {
mockDevice = nil;
[super tearDown];
}
然后,在你的测试中:
-(void)testShouldDoSomethingOnIpad {
id mockDevice = [BaseTestCase createNiceMockDevice];
[[[mockDevice stub] andReturnValue:OCMOCK_VALUE(UIUserInterfaceIdiomPad)] userInterfaceIdiom];
// do something iPad-specific
[mockDevice verify];
}
答案 2 :(得分:0)
另一种方法是将两种变体放入测试中,并在iPhone和iPad模拟器中运行测试。不可否认,这有点麻烦。
-(void)testShouldDoSomething {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// test iPad behavior
} else {
// test iPhone behavior
}
}