您已經編寫了一些 Android 程式碼,現在正好可以用一些測試程式碼來追蹤後續狀況。我們首先會看看一些測試的理念,然後深入研究 Android 專案中自動產生的測試,最後再為 Dice Roller 應用程式編寫您自己的測試!
測試的重要性
- 當應用程式逐漸成長,進行
手動測試
會比編寫自動測試
花費更多精力。 - 開始建構專業級的應用程式時,如果
使用者數量龐大
,測試也會變得十分重要。 - 必須考到許多
不同類型的裝置
,而這些裝置又會執行不同的 Android 版本
。 - 如果您在
發布新的程式碼之前
執行測試,就可以修改現有的程式碼,以免發布的應用程式出現非預期的行為。
自動化測試
是透過軟體執行的測試,而人工測試
則是由會直接與裝置互動的人員執行。若要確保產品使用者都能獲得良好的體驗,自動化測試和手動測試都是非常重要的一環。不過,自動化測試的準確度較高,也可以提升團隊的工作效率,因為員工不必手動執行測試,因此自動化測試的執行速度會比手動測試還要快。
深入探索單元測試
單元測試一律位於 test
目錄中:
- 開啟
app/build.gradle
檔案,然後查看依附元件。有部分依附元件會標記為testImplementation
和androidTestImplementation
,分別是指單元測試
和檢測設備測試
。值得一提的是:
app/build.gradle
1 | testImplementation 'junit:junit:4.12' |
用來驅動單元測試的 JUnit
程式庫,可讓您將程式碼標示為測試,以便採用可以測試應用程式碼的方式編譯和執行應用程式。
- 在
test
目錄中,開啟ExampleUnitTest.kt
檔案。
以下是單元測試的範例:ExampleUnitTest.kt
1 | class ExampleUnitTest { |
註解
雖然你已在 Dice Roller
應用程式中新增了一些程式碼,但可能並未編寫任何測試。因此,這裡只有一些由 Android Studio 自動建立的一般程式碼。這個任意測試可做為預留位置,以便開發人員用來編寫更多相關的測試。
這個程式碼區塊現在只會測試 2 + 2 = 4
。答案當然是正確的。讓我們進一步瞭解實際情況:
- 您必須先從
org.junit.test
程式庫匯入@
Test
註解,然後為測試函式加上該註解。您可以將註解視為一段程式碼的中繼資料標記,可改變程式碼的編譯方式。在這個範例中,@Test
註解可讓編譯器知道以下方法為測試,從而讓該方法據此執行。
函式宣告
註解之後是函式宣告
,在這個範例中為 addition_isCorrect()
函式。在函式中,assertEquals()
函式會宣告預期值
應等於透過商業邏輯取得的實際值
。宣告方法是單元測試的最終目標。
最後,您要宣告從程式碼取得的結果處於特定狀態。如果結果狀態與預期狀態相符,即表示測試通過;如果結果狀態與預期狀態不符,即表示測試失敗。
在這個範例中,程式碼會比較兩個值,因此 assertEquals()
方法會使用 2 個參數,分別是預期值
和實際值
。顧名思義,預期值是您預期出現的特定結果
,在本例中是 4
。實際值代表實際程式碼片段的結果
。一般而言,這樣會測試應用程式本身的程式碼片段。這個範例只有任意的程式碼片段,例如 2 + 2
。請先執行這個測試,看看會發生什麼事。
測試成功
您可透過多種方法在 Android Studio 中執行測試,我們稍後會深入探討。不過,現在先以簡單明瞭為主。
按一下 addition_isCorrect
方法宣告旁的箭頭,然後選取「Run ‘ExampleUnitTest.addition_isCorrect’」。

這就是所謂的正向測試,也就是說,斷言獲得確認。2 + 2
等於 4
。或者,我們可以編寫負向測試,使斷言結果為負。例如:2 + 2
不等於 5
。
在「Run」窗格中,螢幕截圖會如下所示:

許多指標都能表示測試成功,包括綠色勾號,以及所通過測試的數量。
測試失敗
修改測試來看看測試失敗的情形。請將 2 + 2
變更為 2 + 3
,然後再次執行測試。請注意,您只能以產生的程式碼進行實驗,進一步瞭解測試的運作方式。這些變更與 Dice Roller
功能並無任何關聯性。
1 | class ExampleUnitTest { |
完成其餘操作後,螢幕截圖會如下所示:
紅色文字代表測試失敗。在測試結果選單中,按一下項目即會提供錯誤訊息,指出測試失敗的原因。
在這個例子中,錯誤訊息表示斷言失敗,因為預期結果為 4
,但實際值是 5
。由於您將實際值變更為 2 + 3
,但預期值還是 4
,所以這是合理的狀況。您也會看到測試失敗的行。在這個例子中,第 15 行測試失敗,註明為 ExampleUnitTest.kt:15
。
最後,為求測試徹底,請將預期值從 4
變更為 5
,然後再次執行測試。在出現問題的程式碼中,預期值與實際值相符,所以現在測試應已通過。
編寫第一個單元測試
現在您已慢慢熟悉單元測試,您就可以自行編寫與 Dice Roller
應用程式更相關的單元測試。
您應該發現到,Dice Roller
應用程式的主要功能是以隨機號碼產生器為基礎。不過,人所共知,隨機號碼產生器難於測試,因為您無法確定隨機產生號碼的結果。這項測試旨在確保你擲出骰子,或是呼叫 dice
類別上的 roll
方法時,能夠取得正確的數字。您編寫的測試只會測試隨機號碼產生器的結果
不會超出您為產生器指定的數字範圍
。
在
ExampleUnitTest.kt
檔案中,刪除產生的測試方法並匯入陳述式。您的檔案應如下所示:建立
generates_number()
函式:
1 | fun generates_number() { |
- 使用
@Test
註解為generates_number()
方法加上註解。請注意,嘗試呼叫@Test
時,文字會顯示為紅色。這是因為找不到這個註解的斷言
,所以您需要匯入斷言。按下Control+Enter
(在 Mac 上則為Options+Return
) 即可自動執行這項操作。

程式碼現在應如下所示:

- 建立
Dice
物件的執行個體
1 | @Test |
接下來,對這個執行個體呼叫
roll()
方法,並儲存傳回的值。1
2
3
4
5@Test
fun generates_number() {
val dice = Dice(6)
val rollResult = dice.roll()
}最後提出實際斷言即可。換句話說,您需要聲明該方法傳回的值在您傳遞的側側邊數目以內。因此在這個例子中,
該值必須大於 0,且小於 7
。為符合此要求,請使用assertTrue()
方法。請注意,嘗試呼叫assertTrue()
方法時,文字會先顯示為紅色。這是因為找不到這個方法的宣告,所以您必須匯入宣告,做法與處理註解時類似。

然後選擇來自 org.junit.Assert
套件的選項:

如果將游標放在兩個括號之間並按下 Control+P
(在 Mac 上則為 Command+P
),系統會顯示工具提示,當中會顯示方法使用的參數:

assertTrue()
方法有兩個參數:String
和 Boolean
。如果斷言失敗,字串即是控制台中顯示的訊息。布林值是條件陳述式。請將訊息設為:
1 | "The value of rollResult was not between 1 and 6" |
如前文所述,測試隨機號碼是一大挑戰,因為是隨機產生的號碼,所以無法預測號碼的值。所有唯一能做的,就是確保值不會超出特定範圍。請將條件參數設為:
1 | rollResult in 1..6 |
程式碼應該如下所示:
1 | @Test |
- 按一下函式旁邊的箭頭,然後選取「Run ‘ExampleUnitTest.generates_number()’」,結果應顯示測試成功。