使用OCMock模拟[[UIDevice currentDevice] userInterfaceIdiom]

时间:2013-04-11 17:10:46

标签: ios unit-testing ocmock

我正在学习使用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

3 个答案:

答案 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];
}

我一会儿做了more detailed write-up of this approach

答案 2 :(得分:0)

另一种方法是将两种变体放入测试中,并在iPhone和iPad模拟器中运行测试。不可否认,这有点麻烦。

-(void)testShouldDoSomething {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // test iPad behavior
    } else {
        // test iPhone behavior
    }
}