活動是應用程式中所有使用者互動的容器,因此請務必測試應用程式活動在裝置層級事件 (例如下列事件) 期間的行為:
- 其他應用程式 (例如裝置的電話應用程式) 中斷了應用程式的活動。
- 系統會刪除並重新建立活動。
- 使用者將活動置於新的視窗環境,例如子母畫面 (PIP) 或多視窗模式。
特別是,請務必確保活動能正確回應「活動生命週期」一文所述的事件。
本指南說明如何評估應用程式在活動生命週期中轉換不同狀態時,維持資料完整性和良好使用者體驗的能力。
在 Compose 中測試活動
測試以 Jetpack Compose 建構的應用程式時,通常會使用 createAndroidComposeRule 啟動活動,並與 UI 元件互動。
不過,如要測試裝置層級的事件 (例如設定變更,或活動遭系統置於背景或刪除),就必須直接操控活動的生命週期。如要執行這項操作,請使用基礎 ActivityScenario 架構。
Compose 測試規則會自動為您包裝及管理這個情境。 在本指南中,您會看到下列模式,用於彌合新式 UI 測試與標準生命週期管理之間的差距:
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
val scenario = composeTestRule.activityRule.scenario
// ...
}
控管活動狀態
測試應用程式活動時,其中一個重要環節是將應用程式活動置於特定狀態。如要定義測試的「條件」部分,請使用 AndroidX Test 程式庫的 ActivityScenario 執行個體。使用這個類別,您可以將活動置於模擬裝置層級事件的狀態。
ActivityScenario 是跨平台 API,可用於本機單元測試和裝置端整合測試。在實體或虛擬裝置上,ActivityScenario 可提供執行緒安全,在測試的插樁執行緒與執行受測活動的執行緒之間同步處理事件。
這個 API 特別適合評估受測活動在遭到刪除或建立時的行為。本節介紹與這項 API 相關的最常見用途。
建立活動
如要建立受測活動,請新增下列程式碼片段所示的程式碼:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use {
}
}
}
建立活動後,ActivityScenario 會將活動轉換為 RESUMED 狀態。這個狀態表示活動正在執行,且使用者可看見。在這個狀態下,您可以使用 Compose 測試 API 自由與活動的可組合函式互動。
Google 建議您在測試完成時,對活動呼叫 close。
這會清除相關資源,並提升測試穩定性。ActivityScenario 實作 Closeable,因此您可以套用 use 擴充功能,讓活動自動關閉。
或者,您可以使用 createAndroidComposeRule 在每個測試前自動啟動 Activity、處理終止作業,並授予您存取 Compose UI 測試方法和基礎 ActivityScenario 的權限。以下範例說明如何定義規則,並從中取得情境的執行個體:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
val scenario = composeTestRule.activityRule.scenario
}
}
將活動推動到新狀態
如要將活動推動至其他狀態 (例如 CREATED 或 STARTED),請呼叫 moveToState。這項動作會模擬活動因遭到其他應用程式或系統動作中斷,而停止或暫停的情況。
以下程式碼片段顯示 moveToState 的使用範例:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.moveToState(State.CREATED)
}
}
}
判斷目前的活動狀態
如要判斷受測活動的目前狀態,請取得 ActivityScenario 物件中的 state 欄位值。如果活動會重新導向至其他活動或自行完成,檢查受測活動的狀態就特別有幫助,如下列程式碼片段所示:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.onActivity { activity ->
startActivity(Intent(activity, MyOtherActivity::class.java))
}
val originalActivityState = scenario.state
}
}
}
重新建立活動
當裝置資源不足時,系統可能會刪除活動,因此使用者返回應用程式時,應用程式必須重新建立該活動。如要模擬這些情況,請呼叫 recreate:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.recreate()
}
}
}
ActivityScenario 類別會維護活動的已儲存執行個體狀態,以及使用 @NonConfigurationInstance 註解的任何物件。這些物件會載入受測活動的新例項。
擷取活動結果
如要取得與已完成活動相關聯的結果代碼或資料,請取得 ActivityScenario 物件中 result 欄位的值。使用 createAndroidComposeRule 即可輕鬆觸發完成活動的 UI 動作,如以下程式碼片段所示:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testResult() {
composeTestRule.onNodeWithTag("finish_button").performClick()
val scenario = composeTestRule.activityRule.scenario
val resultCode = scenario.result.resultCode
val resultData = scenario.result.resultData
}
}
在活動中觸發動作
ActivityScenario 中的所有方法都是封鎖呼叫,因此 API 會要求您在檢測執行緒中執行這些方法。
如要在受測的活動中觸發動作,請使用 Compose 測試 API 與可組合函式互動:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
@Test fun testEvent() {
composeTestRule.onNodeWithText("Refresh").performClick()
}
}
不過,如果您需要對活動本身呼叫某種方法,則可以使用 onActivity 安全地執行此動作:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEvent() {
launchActivity<MyActivity>().use { scenario ->
scenario.onActivity { activity ->
activity.handleSwipeToRefresh()
}
}
}
}
其他資源
如要進一步瞭解測試,請參閱下列額外資源: