「閒置資源」代表非同步作業,其結果會影響 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,請參閱下列資源。
範例
- IdlingResourceSample:與背景工作同步處理。