UIButton 点击​​的 XCTestCase

Posted

技术标签:

【中文标题】UIButton 点击​​的 XCTestCase【英文标题】:XCTestCase of a UIButton tap 【发布时间】:2019-10-23 09:17:37 【问题描述】:

我正在尝试对 UIViewController 中的按钮点击接线进行单元测试,但我发现这些测试失败,即使正在运行的应用程序中的代码运行良好。

我已经通过删除视图控制器来简化失败的测试,这样简单地离开:

import XCTest

class ButtonTest: XCTestCase 

    var gotTap: XCTestExpectation!

    func test_givenButtonWithTargetForTapAction_whenButtonIsSentTapAction_thenTargetIsCalled() 

        gotTap = expectation(description: "Button tap recieved")

        let button = UIButton()
        button.addTarget(self, action: #selector(tap), for: .touchUpInside)

        button.sendActions(for: .touchUpInside)

        // Fails.
        wait(for: [gotTap], timeout: 0.1)
    

    @objc func tap() 
        gotTap.fulfill()
    

测试做了:

将操作连接到满足测试期望的按钮 使用button.sendActions(for: .touchUpInside)点击按钮 等待期待。

失败是:

异步等待失败:超过 0.1 秒的超时,未实现预期:“按钮点击已收到”。

我不想为此使用 UI 测试。它们的执行速度要慢许多数量级,单元测试在这里应该是理想的。

问题

这是因为UIButton 动作发送需要对响应者链进行一些额外设置而失败吗?还是这里不存在的运行循环?或者是其他东西?如何在不实例化完整的运行应用的情况下在单元测试中进行最低限度的设置? 我最初尝试在没有预期的情况下同步测试按钮点击(这也不起作用,所以我想我会尝试异步) - 如果您可以帮助使其正常工作,请同时说明动作发送是同步还是异步.

【问题讨论】:

【参考方案1】:

关于控制事件的question 具有an answer,控制事件需要UIApplication 实例来发送操作。不幸的是,这个问题并没有说明如何做到这一点。

还有一些代码 here 使用 swizzling 来修补在 UIControl 上发送操作的实现,这样它就不会委托给 UIApplication。它不是用最近的 swift 构建的,因为它依赖于覆盖 initialize - 不过这可能是可以修复的。

我采用的方法是在 UIControl 上实现一个扩展,以便在提供方法 simulateEvent(_ event: UIControl.Event) 的测试中使用,如下所示:

extension UIControl 

    func simulateEvent(_ event: UIControl.Event) 
        for target in allTargets 
            let target = target as NSObjectProtocol
            for actionName in actions(forTarget: target, forControlEvent: event) ?? [] 
                let selector = Selector(actionName)
                target.perform(selector)
            
        
    

这可以被改进以正确检查选择器并确定是否也应该发送发送者和事件,但这是一个合理的概念证明并允许在XCUnitTest 中发送按钮。我也觉得它是非侵入性的,并且接受单元测试没有在完整的应用程序环境中运行的事实,因此测试不能使用完整的响应器处理。

【讨论】:

以上是关于UIButton 点击​​的 XCTestCase的主要内容,如果未能解决你的问题,请参考以下文章

XCTestCase:等待应用空闲

带有Auth0的XCTestCase:如何解除安全警报“XXXX”想要使用“auth0.com”登录

XCTestCase 异步

如何在静态 objc 库中使用 XCTestcase

XCTestCase 不提供项目类

如何在 XCTestCase 中禁用“所有异常”