活動是應用程式中所有使用者互動的容器,因此請務必測試應用程式活動在裝置層級事件 (例如下列事件) 期間的行為:
- 其他應用程式 (例如裝置的電話應用程式) 中斷了應用程式的活動。
- 系統會刪除並重新建立活動。
- 使用者將活動置於新的視窗環境,例如子母畫面 (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() } } } }