如何测试是否已触发UIControlEvents

时间:2016-10-04 11:33:59

标签: ios swift selector xctest nsrunloop

我有一个实现自定义UIControl的库,其方法可以在调用时触发.valueChanged事件。我想测试该行为的方法。

我的自定义控件:

class MyControl: UIControl {
    func fire() {
        sendActions(for: .valueChanged)
    }
}

测试:

import XCTest

class ControlEventObserver: NSObject {
    var expectation: XCTestExpectation!

    init(expectation anExpectation: XCTestExpectation) {
        expectation = anExpectation
    }

    func observe() {
        expectation.fulfill()
    }
}

class Tests: XCTestCase {
    func test() {
        let myExpectation = expectation(description: "event fired")
        let observer = ControlEventObserver(expectation: myExpectation)
        let control = MyControl()
        control.addTarget(observer, action: #selector(ControlEventObserver.observe), for: .valueChanged)
        control.fire()
        waitForExpectations(timeout: 1) { error in
            XCTAssertNil(error)
        }
    }
}

问题是永远不会调用observe方法,因此expectation未得到满足。

问题是:在这种情况下,我们如何测试UIControlEvents?也许我们需要以某种方式强制运行runloop?

编辑1: 请注意,由于我正在测试库,因此我的测试目标没有任何主机应用程序。当测试目标有主机应用程序时,上面的测试就会通过。

2 个答案:

答案 0 :(得分:10)

Apple's documentation for UIControl声明:

  

当发生控件特定事件时,控件将调用任何关联事件   行动方法马上。 通过动作调度动作方法   当前的UIApplication对象,它找到一个合适的对象   如果需要,在响应者链之后处理消息。

在UIControl上调用sendActions(for:)时,控件会调用UIApplication的{​​{1}}将事件传递给注册目标。

由于我在没有任何Host Application的情况下测试库,因此没有sendAction(_:to:from:for:)个对象。因此,不会调度UIApplication事件,也不会调用.valueChanged方法。

答案 1 :(得分:0)

您在测试方法中声明了observer对象。这意味着一旦方法完成,它将从内存中释放,因此不会被调用。在Tests类中创建对类级别观察者的引用,如下所示,它将起作用。

class Tests: XCTestCase {

    var observer: ControlEventObserver!
    func test() {
        let myExpectation = expectation(description: "event fired")
        self.observer = ControlEventObserver(expectation: myExpectation)
        let control = MyControl()
        control.addTarget(observer, action:#selector(ControlEventObserver.observe), for: .valueChanged)
        control.fire()
        waitForExpectations(timeout: 1) { error in
            XCTAssertNil(error)
        }
    }
}

您还需要myExpectation& control以与其他方式相同的方式声明。