【问题标题】:xctest - how to test if a new view loads on a button pressxctest - 如何测试是否在按下按钮时加载新视图
【发布时间】:2013-12-09 02:50:55
【问题描述】:

刚开始使用 xcode 5 和 xctest。如何测试按钮按下时是否加载视图。我以编程方式添加了在单击 rightBarButtonItem 时调用的方法

action:@selector(onSettingsButton)

在 onSettingsButton 中

-(void) onSettingsButton{
    SettingsViewController *svc = [[SettingsViewController alloc] init];
    [self.navigationController pushViewController:svc animated:YES];
}

如何编写 xctest 以确保 SettingsViewController 调出设置视图?谢谢。

【问题讨论】:

    标签: ios mocking xctest


    【解决方案1】:

    您需要一个交互测试——即检查对象之间交互的测试。在这种情况下,您要测试在导航控制器上使用SettingsViewController 调用-pushViewController:animated:。所以我们想将一个模拟对象放入self.navigationController 中,我们可以问:“你按预期调用了吗?”

    我将假设该类的简单名称:MyView。

    我手动执行此操作的方法是子类化并覆盖navigationController。所以在我的测试代码中,我会做这样的事情:

    @interface TestableMyView : MyView
    @property (nonatomic, strong) id mockNavigationController;
    @end
    
    @implementation TestableMyView
    
    - (UINavigationController *)navigationController
    {
        return mockNavigationController;
    }
    
    @end
    

    现在,测试将创建一个 TestableMyView 并设置其 mockNavigationController 属性,而不是创建 MyView。

    这个 mock 可以是任何东西,只要它响应 -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 不能满足我的需要!我被卡住了!”

    【讨论】:

    • 谢谢乔恩。我希望从主控制器获取 navigationControl,获取按钮(navigationItem.rightBarButtonItem)并向其发送新闻消息。然后检查当前可见的控制器是settingsViewController。我不知道如何按下按钮。我可以在代码中找到它。我想重点是我不想检查按钮按下是否有效。我认为确实如此,我只想检查正确的控制器是否出现。那么我在控制器上使用 onSettingsButton 所做的还不够吗?感谢您的耐心等待!
    • 不测试实际的按钮按下。相反,1) 测试按钮是否已连接,2) 其目标是 onSettingsButton,以及 3) 直接调用 onSettingsButton。不需要更多,因为您不需要测试 Apple 的代码。 …您的测试取决于推送视图控制器的实际活动,这可能很慢。它甚至可能在测试完成之前不会生效,因为它是一个实际的 UI 更改。此外,您的测试将您与tipViewController 联系在一起。 …但即使它有效,我希望你看到依赖注入和模拟的一般方法。它会很好地为您服务。
    • 你在[sut onSettingsButton]里面做什么?
    • 那么 mockNavigationController 是如何得到想要的输出的呢?
    • TestableMyView 覆盖普通的-navigationController 以返回模拟。
    【解决方案2】:

    找到一种方法。也许还有其他人..

    - (void)testSettingsViewShowsWhenSettingsButtonIsClicked{
        [self.tipViewController onSettingsButton];
        id temp = self.tipViewController.navigationController.visibleViewController;
        XCTAssertEqual([temp class], [SettingsViewController class], @"Current controller should be Settings view controller");
    }
    

    先调用onSettingsButton,和点击按钮一样,但不是真的。也许这个简单的测试用例没问题?如何模拟实际的印刷机?

    然后从tipviewcontoller获取当前视图,它是应用程序的根视图,并检查它是否是一个SettingsViewController。

    【讨论】:

    • 您好,我使用您的代码进行 swift 但我的导航控制器总是返回 nil,您能解释一下原因吗? Objective C 也会发生这种情况吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 2012-04-25
    • 2012-09-23
    • 2020-10-14
    • 1970-01-01
    • 2016-03-18
    相关资源
    最近更新 更多