9

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

id mockNavController = [OCMockObject mockForClass:[UINavigationController class]];
...
myViewController.navigationController = mockNavController; // readonly!

这篇博文的作者声称找到了解决方案,但忽略了分享。

4

4 回答 4

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];
}
于 2010-12-28T00:02:14.600 回答
2

一个非常晚的响应,但对于后代,我刚刚发现另一种方法是采用基于状态的方法,并将您的视图控制器实际粘贴到一个真正的导航控制器中。然后,您可以戳您的视图控制器并通过检查导航控制器的状态来测试它对导航堆栈的作用。这是一个例子:

it(@"displays the station chooser when you tap the 'Choose station' button", ^{
    // Given
    LaunchViewController *launchViewController = [LaunchViewController newWithNearestStationLocator:nil];
    [launchViewController view];
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:launchViewController];

    // When
    [[launchViewController chooseStationBtn] sendActionsForControlEvents:UIControlEventTouchUpInside];

    // Then
    [[theValue(navController.viewControllers.count) should] equal:theValue(2)];
    [[NSStringFromClass(navController.visibleViewController.class) should] equal:@"StationsViewController"];
});
于 2013-12-21T05:31:17.900 回答
0

有几种可能的解决方案。

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

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

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

于 2010-12-23T21:42:30.600 回答
0

我在测试中使用的一种技术是定义一个将方法添加到主类的类别,以便我可以访问内部属性。您可以尝试使用类别来合成 setter,但您可能需要知道保存导航控制器指针的变量名称。

于 2010-12-22T23:57:25.830 回答