我有一个实现自定义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: 请注意,由于我正在测试库,因此我的测试目标没有任何主机应用程序。当测试目标有主机应用程序时,上面的测试就会通过。
答案 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
以与其他方式相同的方式声明。