1. 事前準備
在先前的程式碼研究室中,我們已說明如何撰寫及執行單元測試和檢測設備測試。這個程式碼研究室介紹了編寫測試時的一些最佳做法,以及如何新增用於測試的特定 Gradle 依附元件。您也會練習撰寫更多單元和檢測設備測試。
必要條件
- 您已在 Android Studio 中開啟現有專案。
- 您已在 Android Studio 中撰寫了單元和檢測設備測試。
- 您已具備在 Android Studio 中瀏覽專案的經驗。
- 您已具備在 Android Studio 中處理
build.gradle
檔案的經驗。
課程內容
- 撰寫測試的基本概念。
- 如何新增測試專用的 Gradle 依附元件。
- 如何透過檢測設備測試,來測試清單。
軟硬體需求
- 已安裝 Android Studio 的電腦。
- Affirmations 應用程式的解決方案程式碼。
下載本程式碼研究室的範例程式碼
在本程式碼研究室中,您將針對 Affirmations 應用程式的解決方案程式碼新增檢測設備測試。
- 前往專案所在的 GitHub 存放區頁面。
- 驗證分支版本名稱與程式碼研究室中指定的分支版本名稱相符。例如,在下列螢幕截圖中,分支版本名稱為「main」。
- 在專案的 GitHub 頁面中,按一下「Code」按鈕,畫面上會出現彈出式視窗。
- 在彈出式視窗中,按一下「Download ZIP」按鈕,將專案儲存至電腦。等待下載作業完成。
- 在電腦中找到該檔案 (可能位於「下載」資料夾中)。
- 按兩下解壓縮 ZIP 檔案。這項操作會建立含有專案檔案的新資料夾。
在 Android Studio 中開啟專案
- 啟動 Android Studio。
- 在「Welcome to Android Studio」視窗中,按一下「Open」。
注意:如果 Android Studio 已開啟,請改為依序選取「File」>「Open」選單選項。
- 在檔案瀏覽器中,前往已解壓縮的專案資料夾所在的位置 (可能位於「Downloads」資料夾中)。
- 按兩下該專案資料夾。
- 等待 Android Studio 開啟專案。
- 按一下「Run」按鈕 即可建構並執行應用程式,請確認應用程式的建構符合預期。
2. 範例應用程式總覽
Affirmations 應用程式是由一個畫面構成,會向使用者顯示搭配確認字詞的圖片清單。
3. 最佳做法
測試程式碼在設計上會與應用程式的商業邏輯有所不同。原因是測試不應包含任何邏輯內容;只單純進行測試而已。因此,測試不應有條件陳述式 (例如 if
或 when
),或者控制流程陳述式 (例如 for
或 while
)。也不得操控值或執行任何實際的運算。
有時候,您的測試可能需要其中一些項目,不過一般而言,請避免使用這些項目。由於我們想要在應用程式中測試這個邏輯類型,因此如果測試中有這類程式碼,可能就會失敗,就像應用程式的程式碼可能會失敗一樣。
我們的單元測試只應從應用程式呼叫部分測試所需的程式碼,並測試呼叫這些程式碼時所產生的程式碼值或狀態。UI 測試則只應測試使用者介面的預期狀態。您可能需要一段時間才能理解這個概念,但沒有關係。我們之後會在程式碼研究室中涵蓋幾個主題,協助說明這個概念。在我們撰寫更多測試的同時,請留意我們撰寫測試的方式。
4. 建立測試目錄
在先前的程式碼研究室中,我們已說明如何建立 androidTest
目錄來進行檢測設備測試。針對 androidTest
目錄和 test
目錄,重複這個專案的流程。這兩者的流程相同,唯一的差別是對於 test
目錄,您必須從「New Directory」下拉式選單中選取「test/java」,而不是「androidTest/java」。接著請為每個名稱為 com.example.affirmations 的新目錄建立新套件。
5. 建立檢測設備測試類別
在「androidTest」->「com.example.affirmations」路徑中,建立名為 AffirmationsListTests.kt
的新類別。
與 Dice Roller 應用程式一樣,Affirmations 只有一個活動。為了測試活動的使用者介面,我們必須指明要啟動活動。試試看能不能自己回想出做法!
- 在新建的類別中加入測試執行器。
@RunWith(AndroidJUnit4::class)
- 為主要活動建立活動情境規則。
@get:Rule
val activity = ActivityScenarioRule(MainActivity::class.java)
- Affirmations 應用程式會顯示圖片及各自的正向肯定語錄清單。使用者介面不允許與項目進行任何互動,例如點擊或滑動。因此,這個應用程式的檢測設備測試只會測試靜態資料。建立名為
scroll_to_item()
的測試方法。請記得加上@Test
的註解。
這項測試應捲動至清單中的特定項目。我們尚未介紹這個方式,因為這需要用到專案尚未參照的方法。在繼續測試之前,需要新增一些測試依附元件。
6. 新增檢測設備測試依附元件
您應該已大致瞭解如何在應用程式的程式碼中,新增要使用的 Gradle 依附元件。透過 Gradle,我們也能新增單元測試和檢測設備測試專用的依附元件。方法是依序前往「app」->「build.gradle」,開啟應用程式層級的 build.gradle
檔案。「依附元件」部分會列出三種實作依附元件的方式:implementation
、testImplementation
和 androidTestImplementation
。
implementation
適用於應用程式本身會使用的依附元件,testImplementation
適用於單元測試中使用的依附元件,androidTestImplementation
則適用於檢測設備測試中使用的依附元件。
- 新增依附元件,允許在檢測設備測試中與
RecyclerView
互動。將下列程式庫新增為androidTestImplementation
:
androidx.test.espresso:espresso-contrib:3.4.0
依附元件看起來會像這樣:
dependencies {
...
androidTestImplementation
'androidx.test.espresso:espresso-contrib:3.4.0'
}
- 接著同步處理專案。
7. 測試 RecyclerView
- 專案同步處理後,請返回
AffirmationsListTests.kt
檔案。提供ViewInteraction
,以使用onView()
執行動作。onView()
方法需要傳入ViewMatcher
。使用withId()
,確認傳入的是用於確認的RecyclerView
ID。立即在ViewInteraction
上呼叫perform()
。也就是新加入的依附元件!現在可以傳入RecyclerViewActions.scrollToPosition<RecyclerView.Viewholder>(9) ViewAction
。
onView(withId(R.id.recycler_view)).perform(
RecyclerViewActions
.scrollToPosition<RecyclerView.ViewHolder>(9)
)
瞭解這一行的語法不太重要,但還是值得看一看。RecyclerViewActions
這個名稱與跟名稱所暗示的一樣:讓您在 RecyclerView
執行測試的類別。scrollToPosition()
是 RecyclerViewActions
類別中的靜態方法,可捲動至指定位置。這個方法會傳回「一般」內容。「一般」內容不在這個程式碼研究室的涵蓋範圍內,但在此案例中,您可以把它想成是 scrollToPosition()
方法,可傳回 RecyclerView
中的所有項目 (可能是任何內容)。
在我們的應用程式中,RecyclerView
中的項目是 ViewHolder
,因此我們會在方法呼叫完成後置入一對角括號,並在其中指定 RecyclerView.ViewHolder
。最後,請傳遞清單中的最後一個位置 (9
)。
- 現在已經可以捲動至
RecyclerView
的所需位置,因此請做出斷言,確保 UI 顯示的是預期資訊。確保當您捲動至最後一個項目後,系統會顯示與最終肯定相關聯的文字。請從ViewInteraction
開始,但這次在新的ViewMatcher
中傳遞 (在本案例中為withText()
)。對於此方法,請傳送包含最後一個肯定語錄文字的字串資源。withText()
方法會根據顯示的文字來識別使用者介面元件。對於這項元件,只需檢查元件中是否顯示所需的文字即可。方法是透過在ViewInteraction
上呼叫check()
。check()
需要ViewAssertion
,因此您可以使用matches()
方法。最後,傳遞isDisplayed()
方法,宣告要顯示使用者介面元件。
onView(withText(R.string.affirmation10))
.check(matches(isDisplayed()))
回到用硬式編碼的方式設定捲動目標位置的附註,有一種方式可透過 RecyclerViewActions
解決此問題。當您不確定清單長度時,可以使用 scrollTo
動作。如要使用 scrollTo
函式,您需要使用 Matcher<View!>!
來尋找特定項目。這可以包含許多項目,但若要達到這項測試的目的,請使用 withText
。將其套用到您剛才編寫的測試後,程式碼看起來會像這樣:
onView(withId(R.id.recycler_view)).perform(
RecyclerViewActions
.scrollTo<RecyclerView.ViewHolder>(
withText(R.string.affirmation10)
)
)
onView(withText(R.string.affirmation10))
.check(matches(isDisplayed())
)
現在一切已準備就緒,隨時可以執行測試。裝置或模擬器應捲動到清單底部,然後才通過測試。如要確保測試結果正確無誤,請將字串 ID 替換成 R.string.affirmation1
。捲動完成後,這個字串資源就不會顯示,且測試應會失敗。
RecyclerViewActions
類別提供的方法有很多種,建議您查看可用的方法。
8. 建立本機測試類別
在「test」->「com.example.affirmations」路徑中,建立名為 AffirmationsAdapterTests.kt
的新類別。
9. 新增本機測試依附元件
- 在本程式碼研究室的前半部,我們討論了三種依附元件實作方式,且您新增了檢測設備測試的依附元件。現在請新增本機測試的依附元件。方法是依序前往「app」->「build.gradle」,並將以下內容新增為單位測試依附元件:
org.mockito:mockito-core:3.12.4
依附元件應如下所示:
dependencies {
...
testImplementation 'org.mockito:mockito-core:3.12.4'
}
- 接著同步處理專案。
10. 測試轉接器
這個應用程式本身不需要進行單元測試,因為沒有足夠的邏輯可以測試。然而,我們可以取得測試各項元件的更多經驗,為日後的測試做準備。
- 在單元測試類別中加入以下這行:
private val context = mock(Context::class.java)
mock()
方法來自我們剛才在專案中實作的程式庫。模擬是單元測試的必要部分,但不在這個程式碼研究室的範圍內。我們會在另一個程式碼研究室中詳細說明模擬功能。在 Android 中,Context
是應用程式目前狀態的結構定義,但別忘了,單元測試是在 JVM 執行,而不是在實際裝置上執行,因此沒有 Context
。這個模擬方法能讓我們建立 Context
的「模擬」執行個體。這個執行個體沒有任何實際的功能,但可用來測試需要結構定義的方法。
- 建立名為
adapter_size()
的函式並加上註解作為測試。這項測試旨在確認轉接器與傳遞至轉接器的清單兩者大小相同。執行方法是建立ItemAdapter
的執行個體,並傳入Datasource
類別中loadAffirmations()
方法所傳回的清單。您也可以建立新的清單並進行測試。如果是單元測試,最佳做法是建立測試專屬的資料,以便我們為這項測試建立自訂名單。
val data = listOf(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2)
)
- 立即建立
ItemAdapter
的執行個體,並傳入在上述步驟中建立的context
和data
變數。
val adapter = ItemAdapter(context, data)
回收器檢視畫面轉接器有一方法,會傳回名為 getItemCount()
的轉接器大小。對於這個應用程式而言,方法如下:
/**
* Return the size of your dataset (invoked by the layout manager)
*/
override fun getItemCount() = dataset.size
- 這是應該測試的方法。這個方法的傳回值必須與您在步驟 2 中建立的清單大小相符。使用
assertEquals()
方法,並比較清單大小和轉接器大小的值。
assertEquals("ItemAdapter is not the correct size", data.size, adapter.itemCount)
您已經熟悉 assertEquals()
方法,但建議您仔細檢查這一行。第一個參數是測試失敗時,會在測試結果中顯示的字串。第二個參數是預期的值。第三個參數是實際值。您的測試類別應如下所示:
- 立即執行測試!
11. 解決方案程式碼
12. 恭喜
在這個程式碼研究室中,您將進行以下作業:
- 瞭解如何新增測試專用的依附元件。
- 瞭解如何透過檢測設備測試與
RecyclerView
互動。 - 討論用於測試的一些基本最佳做法。