測試應用程式活動's 活動

活動可做為應用程式中每個使用者互動的容器,因此請務必測試應用程式活動在裝置層級事件期間的行為,例如:

  • 另一個應用程式 (例如裝置的「電話」應用程式) 會中斷應用程式的活動。
  • 系統會刪除活動,並重新建立活動。
  • 使用者會將活動放在新的視窗環境中,例如子母畫面 (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
    }
}

將活動驅動新狀態

如要將活動驅動至其他狀態 (例如 CREATEDSTARTED),請呼叫 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()
            }
        }
    }
}