活動可做為應用程式中每個使用者互動的容器,因此請務必測試應用程式活動在裝置層級事件期間的行為,例如:
- 另一個應用程式 (例如裝置的「電話」應用程式) 會中斷應用程式的活動。
- 系統會刪除活動,並重新建立活動。
- 使用者會將活動放在新的視窗環境中,例如子母畫面 (PIP) 或多視窗模式。
請特別注意,確保活動能根據活動生命週期所述事件正確運作。
本指南說明如何評估應用程式維持資料完整性的能力,以及在應用程式的生命週期在不同狀態間轉換時,提供良好的使用者體驗。
驅動活動狀態
測試應用程式活動的重要一環,是將應用程式的活動放置在特定狀態。如要定義測試的「特定」部分,請使用 AndroidX Test 程式庫的 ActivityScenario
執行個體。透過這個類別,您可以將活動放置在模擬裝置層級事件的狀態。
ActivityScenario
是一個跨平台 API,同樣可用於本機單元測試和裝置端整合測試。在實際或虛擬裝置上,ActivityScenario
可提供執行緒安全性,讓測試檢測執行緒與執行測試活動的執行緒之間同步處理事件。
這個 API 特別適合用於評估受測活動刪除或建立時的行為。本節介紹與這個 API 有關的最常見用途。
建立活動
如要建立測試中的活動,請新增以下程式碼片段中���示的程式碼:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEvent() { launchActivity<MyActivity>().use { } } }
建立活動後,ActivityScenario
會將活動轉換為 RESUMED
狀態。這個狀態表示活動正在執行,且使用者都能看見。在此狀態下,您可以使用 Espresso UI 測試與活動的 View
元素互動。
Google 建議您在測試完成後,對活動呼叫 close
。這會清除相關資源,並提升測試的穩定性。ActivityScenario
實作 Closeable
,因此您可以使用 Java 程式設計語言套用 use
擴充功能或 try-with-resources
,讓活動自動關閉。
或者,您可以使用 ActivityScenarioRule
,在每次測試前自動呼叫 ActivityScenario.launch
,並在測試拆解期間自動呼叫 ActivityScenario.close
。以下範例說明如何定義規則,並從中取得情境的執行個體:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @get:Rule var activityScenarioRule = activityScenarioRule<MyActivity>() @Test fun testEvent() { val scenario = activityScenarioRule.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
欄位的值,如以下程式碼片段所示:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testResult() { launchActivity<MyActivity>().use { onView(withId(R.id.finish_button)).perform(click()) // Activity under test is now finished. val resultCode = scenario.result.resultCode val resultData = scenario.result.resultData } } }
在活動中觸發動作
ActivityScenario
中的所有方法都是封鎖呼叫,因此 API 會要求您在檢測執行緒中執行這些方法。
如要在受測的活動中觸發動作,請使用 Espresso 檢視畫面比對器與檢視畫面中的元素互動:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEvent() { launchActivity<MyActivity>().use { onView(withId(R.id.refresh)).perform(click()) } } }
不過,如果您需要在活動本身呼叫方法,可以實作 ActivityAction
,以安全的方式進行此操作:
@RunWith(AndroidJUnit4::class) class MyTestSuite { @Test fun testEvent() { launchActivity<MyActivity>().use { scenario -> scenario.onActivity { activity -> activity.handleSwipeToRefresh() } } } }