Espresso 閒置資源

「閒置資源」代表非同步作業,其結果會影響 UI 測試中的後續作業。使用 Espresso 註冊閒置資源後,您就能在測試應用程式時,以更可靠的方式驗證這些非同步作業。

識別何時需要閒置資源

Espresso 提供一組複雜的同步功能。然而,此架構的特性僅適用於在 MessageQueue 上發布訊息的作業,例如 View 子類別,會在螢幕上繪製其內容。

由於 Espresso 不知道任何其他非同步作業 (包括在背景執行緒上執行的作業),因此在這些情況下,Espresso 無法提供同步保證。為了讓 Espresso 得知應用程式的長時間執行作業,您必須將每個作業註冊為閒置資源。

如果您沒有在測試應用程式非同步工作的結果時使用 ID 資源,可能會發現必須使用下列其中一個錯誤解決方法來改善測試可靠性:

  • 將呼叫新增至 Thread.sleep()」。在測試中加入人工延遲後,測試套件需要較長的時間才會完成,而且在較低裝置上執行時,測試有時仍可能失敗。此外,這些延遲無法妥善調整,因為應用程式在日後的版本中可能必須執行更耗時的非同步工作。
  • 實作重試包裝函式,透過迴圈重複檢查應用程式是否仍在執行非同步工作,直到逾時為止。即使您在測試中指定重試次數上限,每次重新執行都會耗用系統資源,尤其是 CPU。
  • 使用 CountDownLatch 的執行個體,可讓一或多個執行緒等待其他執行緒中執行特定作業數為止。您必須指定這些物件的時間長度,否則應用程式可能會無限期封鎖。後者也會讓程式碼產生不必要的複雜度,使維護更加困難。

Espresso 可讓您從測試中移除這些不可靠的解決方法,而是將應用程式的非同步工作註冊為閒置資源。

常見用途

在測試中執行與下列範例類似的作業時,請考慮使用閒置資源:

  • 從網際網路或本機資料來源載入資料
  • 與資料庫和回呼建立連線
  • 管理服務:使用系統服務或 IntentService 的執行個體。
  • 執行複雜的商業邏輯,例如點陣圖轉換。

在這些作業更新 UI 以供測試進行驗證時,請務必註冊閒置資源。

閒置資源導入範例

以下清單說明可整合至應用程式的幾種閒置資源實作範例:

CountingIdlingResource
保留當前工作的計數器。如果計數器為零,相關聯的資源就會視為閒置。這項功能與 Semaphore 非常類似。在大多數情況下,這個實作就足以在測試期間管理應用程式的非同步工作。
UriIdlingResource
CountingIdlingResource 類似,但計數器在一段時間內必須是零,系統才會將資源視為閒置。這額外的等待期間會將連續網路要求納入考量。執行緒中的應用程式可能會在收到對前一個要求的回應後,立即發出新的要求。
IdlingThreadPoolExecutor
自訂 ThreadPoolExecutor 的實作,追蹤所建立執行緒集區內執行中的工作總數。這個類別使用 CountingIdlingResource 來維持有效工作的計數器。
IdlingScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 的自訂實作。它提供的功能與 IdlingThreadPoolExecutor 類別相同,但也可以追蹤已排定在未來或已排定定期執行的工作。

建立自己的閒置資源

在應用程式測試中使用 ID 資源時,您可能需要提供自訂資源管理或記錄功能。在這些情況下,上一節列出的實作項目可能就已足夠。如果是這種情況,您可以擴充其中一個閒置資源實作,或自行建立。

如果您要實作自己的閒置資源功能,請記住下列最佳做法,特別是第一個做法:

在閒置檢查之外叫用閒置狀態的轉換。
應用程式進入閒置狀態後,請在 isIdleNow() 的所有實作之外呼叫 onTransitionToIdle()。如此一來,Espresso 就不會執行不必要的檢查,也不會判斷特定的閒置資源是否處於閒置狀態。

以下程式碼片段說明這項建議:

Kotlin

fun isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

fun backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}

Java

public void isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

public void backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}
事先註冊閒置資源。

與閒置資源相關聯的同步處理優勢只會在 Espresso 首次叫用該資源的 isIdleNow() 方法後生效。

以下列出這項屬性的幾個範例:

  • 如果您在加上 @Before 註解的方法中註冊閒置資源,則每個測試的第一行都會使用閒置資源。
  • 如果您在測試中註冊閒置資源,會在下一個 Espresso 動作期間生效。即使下一個動作與註冊閒置資源的陳述式相同,仍會發生此行為。
使用完畢後取消註冊閒置資源。

為了保留系統資源,建議您在不再需要的資源時立即取消註冊。舉例來說,如果您在加上 @Before 註解的方法中註冊閒置資源,建議您透過加上 @After 註解的對應方法取消註冊這項資源。

使用閒置註冊資料庫註冊及取消註冊閒置資源。

將這個容器用於應用程式的閒置資源,即可視需要重複註冊及取消註冊閒置資源,並觀察一致的行為。

僅在閒置資源中維護簡易的應用程式狀態。

例如,您實作及註冊的 ID 資源不應包含 View 物件的參照。

註冊閒置資源

Espresso 提供容器類別,您可以在其中放置應用程式的閒置資源。這個類別稱為 IdlingRegistry,是獨立構件,不會對應用程式造成最小負擔。這個類別也可讓您採取下列步驟,改善應用程式的可維護性:

  • 在應用程式測試中建立 IdlingRegistry 的參照,而非其中包含的閒置資源。
  • 針對每個建構變數使用的閒置資源集合,應保持差異。
  • 在應用程式服務中定義閒置資源,而不是在參照這些服務的 UI 元件中定義。

將閒置資源整合至應用程式

雖然您可以透過幾種不同的方式將 ID 資源新增至應用程式,但其中一個方法特別是維持應用程式的封裝,同時仍可讓您指定特定閒置資源代表的特定作業。

在應用程式中新增閒置資源時,我們「強烈建議」將閒置的資源邏輯放入應用程式本身,並在測試中只執行註冊和取消註冊作業。

雖然藉由遵循此方法,在正式版程式碼中使用僅供測試用介面的異常情況,您仍可以將現有程式碼包裝成閒置資源,維持應用程式的 APK 大小和方法計數。

替代方法

如果您不想在應用程式正式版程式碼中放置閒置資源邏輯,請參考下列其他可行的整合策略:

  • 建立建構變數 (例如 Gradle 的變種版本),並且只在應用程式的偵錯版本中使用閒置資源。
  • 使用依附元件插入架構 (例如 Dagger),將應用程式的閒置資源依附元件圖表插入測試。如果您使用的是 Dagger 2,則插入本身應來自子元件。
  • 在應用程式測試中實作 ID 資源,並公開應用程式實作中需要同步處理的部分。

    注意: 雖然這項設計決策似乎會建立閒置資源的獨立參照,但除了最簡單的應用程式之外,封裝功能也無法正常運作。

其他資源

如要進一步瞭解如何在 Android 測試中使用 Espresso,請參閱下列資源。

範例