在UIViewController上设置readonly navigationController属性以进行模拟

tit*_*coy 9 cocoa-touch unit-testing objective-c ocmock

我使用OCMock创建了一个模拟UINavigationController.但是,我不能将它分配给UIViewController的navigationController属性,因为该属性是只读的.

id mockNavController = [OCMockObject mockForClass:[UINavigationController class]];
...
myViewController.navigationController = mockNavController; // readonly!
Run Code Online (Sandbox Code Playgroud)

这篇博文的作者声称找到了一个解决方案,却忽略了分享它.

Chr*_*lay 17

没有必要创建一个允许您设置navigationController属性的mutator,因为您可以模拟返回它的访问器.我是这样做的:

-(void)testTappingSettingsButtonShouldDisplaySettings {
    MyController *myController = [[MyController alloc] init];

    // expect the nav controller to push a settings controller
    id mockNavigationController = [OCMockObject mockForClass:[UINavigationController class]];
    [[mockNavigationController expect] pushViewController:[OCMArg any] animated:YES];

    // set up myController to return the mocked navigation controller
    id mockController = [OCMockObject partialMockForObject:myController];
    [[[mockController expect] andReturn:mockNavigationController] navigationController];

    [myController settingsButtonTapped];

    [mockNavigationController verify];
    [mockController verify];
    [myController release];
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*nah 0

有几种可能的解决方案。

您可以调用 navigationController 的私有设置器,但它可能不存在或在所有情况下都可靠地工作。

您可以遵循 Derek 的建议并创建一个类别来重新定义 UIViewController 上的 navigationController 属性。对 navigationController 属性的访问应该是安全的,但如果 UIViewController 在任何地方直接访问支持 ivar,并且您没有在类别中使用相同的 ivar,那么您可能会看到意外的行为。

您可以使用 UINavigationController 的部分模拟,如http://blog.carbon Five.com/2010/03/10/testing-view-controllers/中所示。在这种情况下,您的测试并不像您希望的那样孤立,但至少 UIViewController 超类和 UINavigationController 的私有行为应该保持不变。