簡體   English   中英

UIButton 抽頭的 XCTestCase

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM