測試應用程式活動'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()
            }
        }
    }
}