![](/img/trans.png)
[英]XCTestCase: Tap on cell in collectionView with IndexPath
[英]XCTestCase of a UIButton tap
我正在嘗試對UIViewController
中的按鈕水龍頭接線進行單元測試,但我發現這些測試失敗,即使正在運行的應用程序中的代碼運行良好。
我通過刪除視圖 controller 簡化了失敗的測試,這樣簡單地離開:
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
動作發送需要對響應者鏈進行一些額外設置而失敗嗎? 還是這里不存在的運行循環? 或者是其他東西? 如何在不實例化完整運行的應用程序的情況下在單元測試中進行最低限度的設置? 一個關於控制事件的問題有一個答案是控制事件需要一個UIApplication
實例來發送動作。 不幸的是,這個問題並未表明如何做到這一點。
這里還有一些代碼使用 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
中發送按鈕。 我也覺得它是非侵入性的,並且接受單元測試沒有在完整的應用程序環境中運行的事實,因此測試不能使用完整的響應程序處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.