簡體   English   中英

使用Xcode UI測試來測試底層框架行為

[英]Using Xcode UI tests to test underlying framework behavior

我正在構建一個iOS框架,用於收集有關iOS應用程序中各種事件的信息,並執行本地和遠程分析。 其中一些事件無法在應用程序之外進行測試:例如,查看控制器轉換。 為了測試這些事件,我構建了一個測試iOS應用程序,並希望使用Xcode UI測試:

  • 通過點擊將VC推送到導航控制器的按鈕,或通過切換到選項卡控制器中的其他選項卡來啟動視圖控制器轉換

  • 驗證框架是否能夠檢測到視圖控制器轉換並生成必要的事件(例如,將它們發送到服務器)

問題是Xcode UI測試在應用程序外部運行,因此我無法訪問任何共享對象來驗證框架是否正常運行。 我也無法插入任何模擬對象,因為我再次無法訪問應用程序進程中加載​​的框架。

我試圖在一種測試模式下加載框架並讓它更新一個標簽,其中包含一些UI測試然后能夠讀取的結果。 但即便這樣也很困難,因為XCUIElement並沒有給我這個元素的實際文本; 我只能查詢帶有一些預定義文本的元素。 我可以對此進行一些工作,但對於一些應該相當微不足道的事情,這似乎是一種非常迂回的方法。

有沒有更好的替代方法來測試只能在正在運行的應用程序中模擬的事件,然后驗證我的框架能夠檢測並處理它們? 除了查看控制器轉換之外,我還對觸摸交互,加速度計事件以及無法在應用程序外部模擬的其他功能感興趣。 當然,我可以模擬這些事件進行單元測試,但我還想自動測試,當這些事件發生在實際應用程序中時,在我的框架中生成正確的響應。

您可以嘗試使用SBTUITestTunnel 此庫擴展了UI測試的功能,添加了一些可能在像您這樣的情況下派上用場的功能。

網絡監控

該庫允許您的測試目標收集在應用程序中調用的網絡調用。 用法很簡單:

func testThatNetworkAfterEvent() {
  // Use SBTUITunneledApplication instead of XCUIApplication
  let app = SBTUITunneledApplication()
  app.launchTunnelWithOptions([SBTUITunneledApplicationLaunchOptionResetFilesystem]) {
      // do additional setup before the app launches
      // i.e. prepare stub request, start monitoring requests
  }

  app.monitorRequestsWithRegex("(.*)myserver(.*)") // monitor all requests containing myserver

  // 1. Interact with UI tapping elements that generate your events

  // 2. Wait for events to be sent. This could be determined from the UI (a UIActivitiIndicator somewhere in your app?) or ultimately if you have no other option with an NSThread.sleepfortimeinterval

  // 3. Once ready flush calls and get the list of requests
  let requests: [SBTMonitoredNetworkRequest] = app.monitoredRequestsFlushAll()

  for request in requests {
      let requestBody = request.request!.HTTPBody // HTTP Body in POST request?
      let responseJSON = request.responseJSON
      let requestTime = request.requestTime // How long did the request take?
  }
}

網絡監控的好處是所有測試代碼和邏輯都包含在您的測試目標中。

自定義代碼塊

在其他用例中,您需要在測試目標中方便地調用自定義代碼,您也可以這樣做。

在應用目標中注冊代碼塊

SBTUITestTunnelServer.registerCustomCommandNamed("myCustomCommandKey") {
    injectedObject in
    // this block will be invoked from app.performCustomCommandNamed()

    return "any object you like"
}

並從測試目標中調用它

func testThatNetworkAfterEvent() {
  let app = ....

  // at the right time
  let objFromBlock = app.performCustomCommandNamed("myCustomCommand", object: someObjectToInject)
}

目前,您只能從測試目標 - >應用目標中注入數據。 如果您需要相反的方法,可以將該數據存儲在NSUserDefaults中,並使用SBTUIApplication的userDefaultsObjectForKey()方法獲取它。

我個人不喜歡在應用程序的目標中混合使用標准代碼和測試代碼的想法,所以我建議只在真正需要時使用它。

編輯

我已經更新了庫並從願景0.9.23開始,您現在可以將任何對象從塊傳遞回測試目標。 不再需要變通辦法!

完成任務並不是一種自動化的方法,但確實使用斷點作為中間方式,至少在您自動啟動之前。 您可以添加符號斷點來點擊UI方法,例如[UIWindow setRootViewController:],viewWillAppear等。

您可以明確定義模塊,條件和操作,以便每當有人查看您的VC時,都會執行一些可能對您有所幫助的操作。

如果你可以在一些viewDidAppear上使用一個簡單的“po myEvent”從你的框架中打印出一些東西,你就可以了。 我從未嘗試過使用更高級的方法作為動作,但也可以這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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