測試 Android 應用程式的基礎知識

本頁概述測試 Android 應用程式的核心原則,包括核心最佳做法和其優點。

測試的好處

測試是應用程式開發流程中不可或缺的一環。藉由對應用程式持續執行測試,您可以在公開發布應用程式前,驗證應用程式的正確性、功能行為和可用性。

您可以在瀏覽應用程式時手動測試應用程式。您可能會使用不同的裝置和模擬器、變更系統語言,並嘗試產生每個使用者錯誤或細查每個使用者流程。

不過,手動測試的縮放比例會不佳,而且很容易忽略應用程式行為中的迴歸。自動化測試:「自動化測試」是指使用工具為您執行測試,不但速度更快、更可重複,也通常能在開發階段初期,為您提供更多可做為行動依據的意見回饋。

Android 的測試類型

行動應用程式相當複雜,在許多環境中都能順利運作。因此,測試有很多類型。

主旨

舉例來說,視 subject 劃分不同的測試類型:

  • 功能測試:應用程式能執行預期的功能嗎?
  • 效能測試:這項功能是否能快速有效地?
  • 無障礙測試:這項功能是否能與無障礙服務搭配運作?
  • 相容性測試:是否可在所有裝置和 API 級別上順利運作?

範圍

測試也會依「大小」或「隔離程度」而有所不同:

  • 單元測試小型測試,只能驗證應用程式的極小部分,例如方法或類別。
  • 端對端測試或大型測試會同時驗證應用程式的較大部分,例如整個螢幕或使用者流程。
  • 中等測試介於兩個或多個單元之間,並檢查是否整合
測試可分為小、中或大。
圖 1:一般應用程式中的測試範圍。

分類測試的方式有很多種。不過,對應用程式開發人員來說,最重要的區別在於執行測試。

檢測設備與本機測試

您可以在 Android 裝置或其他電腦上執行測試:

  • 設備測試在 Android 裝置 (實體或模擬) 上執行。應用程式會與測試應用程式一起建構及安裝,以便插入指令及讀取狀態。檢測設備測試通常為 UI 測試,包含啟動應用程式,然後與應用程式互動。
  • 本機測試會在開發機器或伺服器上執行,因此也稱為「主機端測試」。這些 API 通常較小、快速,將受測試的主體與應用程式的其餘部分區隔開來。
測試可以透過裝置進行檢測設備測試,或在開發機器上執行本機測試。
圖 2:不同類型的測試取決於執行位置。

單元測試並非本機進行,而且並非所有端對端測試都會在裝置上執行。例如:

  • 大型本機測試:您可以使用在本機執行的 Android 模擬器,例如 Robolectric
  • 小型檢測設備測試:您可以驗證程式碼是否能與架構功能 (例如 SQLite 資料庫) 搭配使用,您可以在多部裝置上執行這項測試,藉此檢查 SQLite 與多個版本的整合情形。

範例

以下程式碼片段示範如何在點按元素並驗證其他元素的檢測設備 UI 測試中與 UI 互動。

Espresso

// When the Continue button is clicked
onView(withText("Continue"))
    .perform(click())

// Then the Welcome screen is displayed
onView(withText("Welcome"))
    .check(matches(isDisplayed()))

Compose UI

// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()

// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()

下列程式碼片段是 ViewModel (本機、主機端測試) 單元測試的一部分:

// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)

// When data is loaded
viewModel.loadData()

// Then it should be exposing data
assertTrue(viewModel.data != null)

定義測試策略

在理想情況下,您應在應用程式相容的每部裝置上測試應用程式中的每一行程式碼。可惜的是,這種方法太慢 且成本昂貴

良好的測試策略可在測試的準確度、速度和可靠性之間取得適當平衡。測試環境與實際裝置的相似性會決定測試的擬真度。在模擬裝置或實體裝置本身上執行高精確度測試。低擬真度測試可能會在本機工作站的 JVM 上執行。高擬真度測試通常速度較慢,且需要更多資源,因此並非所有測試都應執行高精確度測試。

不穩定的測試

即使在設計和實作正確的情況下,仍會發生錯誤。舉例來說,在實體裝置上執行測試時,自動更新功能可能會在測試期間啟動,並導致更新失敗。程式碼中細微的競爭狀況可能只有一小部分的時間發生。未通過 100% 時間的測試都會不穩定

可測試的架構

根據可測試的應用程式架構,程式碼採用的結構,可讓您輕鬆獨立測試程式碼的不同部分。可測試的架構還有其他優點,例如更佳的可讀性、可維護性、擴充性和重複使用性。

「無法測試」的架構會產生下列結果:

  • 規模較大、速度較慢、不穩定的測試。無法進行單元測試的類別可能會涵蓋在較大的整合測試或 UI 測試中。
  • 可減少測試不同情境的機會。大型測試的執行速度較慢,因此測試應用程式的所有可能狀態可能並不切實際。

如要進一步瞭解架構指南,請參閱「應用程式架構指南」。

分離的方法

如果您可以從其他函式中擷取部分函式、類別或模組的部分,那麼進行測試會比較簡單,也更有效率。這種做法稱為分離,是可測試架構最重要的概念。

常見的分離技巧包括:

  • 將應用程式分割為多個圖層,例如「呈現」、「網域」和資料。您也可以將應用程式分割成「模組」,每個功能各一個。
  • 請避免將邏輯新增至含有大型依附元件的實體,例如活動和片段。您可以使用這些類別做為架構的進入點,並將 UI 和商業邏輯移至其他位置,例如可組合項、ViewModel 或網域層。
  • 避免在包含商業邏輯的類別中直接架構依附元件。例如,不要在 ViewModel 中使用 Android Context
  • 讓依附元件很容易取代。舉例來說,您可以使用「介面」,而非具體實作。即使不使用 DI 架構,也請使用依附元件插入功能。

後續步驟

現在您已瞭解應測試的原因和兩種主要測試類型,請參閱測試項目一文。

或者,如要建立第一個測試並學習,請參閱測試程式碼研究室