行動應用程式和架構的非同步性質,往往會導致難以編寫可靠且可重複的測試。插入使用者事件時,測試架構必須等待應用程式完成回應,這可能是變更畫面上的部分文字,到完整重新建立活動。如果測試沒有確定性行為,就屬於「不穩定」。
Compose 或 Espresso 等新式架構的設計理念是為了測試,因此可確保在下一個測試動作或斷言之前,UI 會處於閒置狀態。這就是同步處理。
測試同步處理
執行測試未知的非同步或背景作業時,仍可能發生問題,例如從資料庫載入資料或顯示無限動畫。
為提高測試套件的可靠性,您可以安裝可追蹤背景作業的方式,例如 Espresso 閒置資源。此外,您也可以為測試版本取代模組,以便查詢閒置狀態或改善同步作業,例如協同程式的 TestDispatcher 或 RxJava 的 RxIdler。
如何提升穩定性
大規模測試可同時找出許多迴歸問題,因為這類測試會測試應用程式的多個元件。這類測試通常會在模擬器或裝置上執行,因此精確度很高。雖然大型端對端測試可提供全面的涵蓋率,但更容易發生偶發性失敗。
您可以採取以下主要措施來減少不穩定性:
- 正確設定裝置
- 避免同步處理問題
- 實作重試
如要使用 Compose 或 Espresso 建立大型測試,通常會啟動其中一個活動,並以使用者的方式導覽,藉此驗證 UI 是否正常運作,例如使用斷言或螢幕截圖測試。
其他架構 (例如 UI Automator) 可讓您與系統 UI 和其他應用程式互動,因此範圍更廣泛。不過,UI Automator 測試可能需要更多手動同步作業,因此可靠性較低。
設定裝置
首先,為了提高測試的可靠性,您必須確保裝置的作業系統不會意外中斷測試執行作業。例如,當系統更新對話方塊顯示在其他應用程式上層,或是磁碟空間不足時。
裝置農場供應商會設定裝置和模擬器,因此您通常不需要採取任何行動。不過,這些類別可能會針對特殊情況提供專屬的設定指示。
Gradle 管理的裝置
如果您自行管理模擬器,可以使用 Gradle 管理的裝置定義要使用哪些裝置執行測試:
android {
testOptions {
managedDevices {
localDevices {
create("pixel2api30") {
// Use device profiles you typically see in Android Studio.
device = "Pixel 2"
// Use only API levels 27 and higher.
apiLevel = 30
// To include Google services, use "google".
systemImageSource = "aosp"
}
}
}
}
}
在這個設定下,下列指令會建立模擬器映像檔、啟動執行個體、執行測試,然後關閉執行個體。
./gradlew pixel2api30DebugAndroidTest
Gradle 管理的裝置包含裝置中斷連線時重試的機制,以及其他改善措施。
避免同步處理問題
執行背景或非同步作業的元件可能會導致測試失敗,因為測試陳述式是在 UI 準備就緒前執行。測試範圍越廣,出現不穩定的可能性就越高。這些同步問題是導致不穩定的主要原因,因為測試架構需要推斷活動是否已「完成」載入,或是應等待更長的時間。
解決方案
您可以使用 Espresso 的閒置資源來指出應用程式何時處於忙碌狀態,但很難追蹤每個非同步作業,尤其是在非常龐大的端對端測試中。此外,如果不想讓測試中的程式碼受到影響,就很難安裝空轉資源。
您可以讓測試等待特定條件滿足,而非估計活動是否忙碌。舉例來說,您可以等待特定文字或元件顯示在 UI 中。
Compose 會在 ComposeTestRule
中提供一系列測試 API,用於等待不同的比對器:
fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeout: Long = 1000L)
fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeout: Long = 1000L)
fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeout: Long = 1000L)
fun waitUntilNodeCount(matcher: SemanticsMatcher, count: Int, timeout: Long = 1000L)
以及通用 API,可接收任何傳回布林值的函式:
fun waitUntil(timeoutMillis: Long, condition: () -> Boolean): Unit
使用範例:
composeTestRule.waitUntilExactlyOneExists(hasText("Continue")</code>)</p></td>
重試機制
您應該修正不穩定的測試,但有時導致測試失敗的條件非常罕見,因此很難重現。雖然您應該隨時追蹤並修正不穩定的測試,但重試機制可執行多次測試,直到測試通過為止,有助於維持開發人員的生產力。
重試必須在多個層級進行,才能避免發生問題,例如:
- 連線到裝置的逾時或連線中斷
- 單一測試失敗
安裝或設定重試作業取決於您的測試架構和基礎架構,但一般機制包括:
- 重試任何測試的次數的 JUnit 規則
- CI 工作流程中的重試動作或步驟
- 系統會在無回應時重新啟動模擬器,例如 Gradle 管理的裝置。