您需要一个交互测试——即检查对象之间交互的测试。在这种情况下,您要测试-pushViewController:animated:
在导航控制器上调用的SettingsViewController
. 所以我们想放入一个模拟对象self.navigationController
,我们可以问:“你被按预期调用了吗?”
我将为该类假设一个简单的名称:MyView。
我手动执行此操作的方式是 Subclass 和 Override navigationController
。所以在我的测试代码中,我会做这样的事情:
@interface TestableMyView : MyView
@property (nonatomic, strong) id mockNavigationController;
@end
@implementation TestableMyView
- (UINavigationController *)navigationController
{
return mockNavigationController;
}
@end
mockNavigationController
现在,测试将创建一个 TestableMyView 并设置它的属性,而不是创建一个 MyView 。
这个模拟可以是任何东西,只要它响应-pushViewController:animated:
并记录参数。这是一个简单的例子,手动:
@interface MockNavigationController : NSObject
@property (nonatomic) int pushViewControllerCount;
@property (nonatomic, strong) UIViewController *pushedViewController;
@property (nonatomic) BOOL wasPushViewControllerAnimated;
@end
@implementation MockNavigationController
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
self.pushViewControllerCount += 1;
self.pushedViewController = viewController;
self.wasPushViewControllerAnimated = animated;
}
@end
最后,这是一个测试:
- (void)testOnSettingsButton_ShouldPushSettingsViewController
{
// given
MockNavigationController *mockNav = [[MockNavigationController alloc] init];
TestableMyView *sut = [[TestableMyView alloc] init];
sut.mockNavigationController = mockNav;
// when
[sut onSettingsButton];
// then
XCTAssertEquals(1, mockNav.pushViewControllerCount);
XCTAssertTrue([mockNav.pushedViewController isKindOfClass:[SettingsViewController class]]);
}
这些事情可以通过使用模拟对象框架来简化,例如 OCMock、OCMockito 或 Kiwi 的模拟。但我认为先手动开始会有所帮助,以便您理解这些概念。然后选择有帮助的工具。如果你知道如何手工完成,你永远不会说,“模拟框架 X 不能满足我的需要!我被卡住了!”