在 Android 中使用測試替身

測試元素或元素系統時,請隔離測試。舉例來說,如果要測試 ViewModel,您不需要啟動模擬器並發布 UI,因為 ViewModel 不會 (或不應) 依賴 Android 架構。

不過,測試的對象可能依賴其他對象才能運作。舉例來說,ViewModel 可能會依賴資料存放區才能運作。

當您需要為受測試的主體提供依附元件時,常見做法是建立測試替身 (或測試物件)。測試影本是看起來和應用程式中的元件一樣的物件,但會在測試中建立,以提供特定行為或資料。主要優點是可讓測試更快速、更簡單。

測試雙胞胎的類型

測試雙胞胎有以下幾種類型:

偽造 測試雙重代理程式,具有類別的「可用」實作項目,但實作方式適合測試,但不適合用於實際工作環境。

範例:記憶體內資料庫。

假資料不需要模擬架構,且體積輕巧。這是首選做法。

模擬 一個測試雙重,代表您的程式碼設定運作模式,且在互動方面具有期望。如果模擬資料的互動行為不符合您定義的條件,測試就會失敗。模擬資料通常是使用模擬架構建立,以便達成上述所有目標。

範例:驗證資料庫中的方法是否只呼叫一次。

空白 一個測試雙倍的測試可正常運作,但這不會預期您的互動情形。通常是使用模擬架構建立。為求簡單,建議使用假資料,而非虛擬資料。
虛擬 傳遞但未使用的測試影本,例如您只需要將其做為參數提供。

範例:做為點擊回呼傳遞的空白函式。

間諜 實體物件的包裝函式,可用於追蹤一些額外資訊,類似模擬物件。通常會避免使用這些方法,以免增加複雜度。因此,假的實作或模擬比間諜更為理想。
陰影 在 Robolectric 中使用的假資料。

假使意圖

假設您想要對 ViewModel 進行單元測試,該 ViewModel 依附於名為 UserRepository 的介面,並將第一位使用者的姓名公開到 UI。您可以實作介面並傳回已知資料,藉此建立假的測試雙重。

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

這個假的 UserRepository 不需要依賴實際工作環境版本會使用的本機和遠端資料來源。這個檔案位於測試來源集,不會隨實際工作環境應用程式一併發布。

假依附元件可傳回已知資料,而不需要依附遠端資料來源
圖 1:單元測試中的假依附元件。

以下測試會驗證 ViewModel 是否正確將第一個使用者名稱公開給檢視畫面。

@Test
fun viewModelA_loadsUsers_showsFirstUser() {
    // Given a VM using fake data
    val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init

    // Verify that the exposed data is correct
    assertEquals(viewModel.firstUserName, UserAlice.name)
}

在單元測試中,您可以將 UserRepository 換成假工具,因為 ViewModel 是由測試人員建立。不過,在大型測試中替換任意元素可能相當困難。

取代元件和插入依附元件

如果測試無法控制測試系統的建立作業,則替換測試替身元件會變得更複雜,而且應用程式架構必須遵循可測試的設計。

即使是大型端對端測試,也可以透過使用測試替身來發揮效益,例如在應用程式中瀏覽完整使用者流程的設備測試。在這種情況下,您可能需要讓測試密封。密封測試可避免所有外部依附元件,例如從網際網路擷取資料。這有助於提升可靠性和效能。

圖 2:大規模測試,涵蓋大部分應用程式並模擬遠端資料。

您可以手動設計應用程式來達到這項彈性,但還是建議您使用 Hilt依附元件插入架構,在測試期間替換應用程式中的元件。請參閱 Hilt 測試指南

後續步驟

測試策略」頁面說明如何使用不同類型的測試來提高工作效率。