Android TDD 系列 — 12 UI 測試:使用Espresso

Evan Chen
Evan Android Note
Published in
8 min readOct 1, 2019

UI 測試在Android 的所有測試裡執行起來最花費時間的,成本最高。但當我們需要測試使用者如何使用App時,仍是有撰寫UI測試的必要。Espresso是一個讓你可以撰寫Android UI測試的框架。你可以用id或文字的方式來取得一個元件,模擬使用者點擊、輸入資料等使用者行為及驗證App上是否有出現預期的功能。

實體書,內容更豐富完整!
Android TDD 測試驅動開發:從UnitTest、TDD到DevOps實踐

在指定Id上的EditText上輸入文字

//在id為someId的元件上輸入Some Text
onView(withId(R.id.someId)).perform(typeText("Some Text"))

如果你無法用指定id的方式來取得元件,也可以用withText比對文字的方式來取得元件。

//取得是否有文字為Some text的元件存在
onView(withText("Some text")).check(matches(isDisplayed()))

點擊按鈕

//點擊Id為button的元件
onView(withId(R.id.button)).perform(click())

環境設定

在buide.gralde加上

dependencies {
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

範例

我們延續之前的範例:註冊功能,來做UI測試。

UI測試的程式跟Instrumented test 一樣都是放在androidTest裡
新增測試類別RegisterTest

在RegisterTest 上方加上@LargeTest
當你會用到網路存取資料、資料庫、多執行緒等等較花費時間,在你的測試類別上方加上@LargeTest
測試執行時間會超過1秒的,一般都會被歸為LargeTest。

@LargeTest
class RegisterTest {

}

開始測試

首先要開啟我們要測試的Activity。使用ActivityTestRule來設定測試目標Activity, 可以讓你在開始測試之前,先開啟被測試的Activity。

class RegisterTest {
@Rule
@JvmField
var activityActivityTestRule = ActivityTestRule(MainActivity::class.java)
}

我們先為註冊成功撰寫一個UI測試,當輸入正確的帳號密碼時,會開啟至下一頁顯示註冊成功。

@Test
fun rightPassword_should_startActivity() {
//輸入帳號
onView(withId(R.id.loginId)).perform(typeText("a123456789"), ViewActions.closeSoftKeyboard())
//輸入密碼
onView(withId(R.id.password)).perform(typeText("a111111111"), ViewActions.closeSoftKeyboard())
//點選註冊按鈕
onView(withId(R.id.send)).perform(click())
//註冊成功,導至成功頁。
onView(withText("註冊成功")).check(matches(isDisplayed()))
}

執行UI測試的方式一樣是按綠色的三角型,就可以看到模擬器被開起來自動測試。

註冊失敗也是需要測試的。註冊失敗需要驗證是否有Alert。

@Test
fun wrongPassword_should_alert() {
//輸入帳號
onView(withId(R.id.loginId)).perform(typeText("a123456789"), ViewActions.closeSoftKeyboard())
//輸入密碼
onView(withId(R.id.password)).perform(typeText("1234"), ViewActions.closeSoftKeyboard())
//點選註冊按鈕
onView(withId(R.id.send)).perform(click())
//註冊失敗,Alert
onView(withText("錯誤"))
.inRoot(isDialog())
.check(matches(isDisplayed()))
}

一樣執行測試,就可以看到測試通過的綠燈了。

這裡我們重構一下測試程式碼,下面這段是在輸入正確帳密的程式。

@Test
fun rightPassword_should_startActivity() {
//輸入帳號
onView(withId(R.id.loginId)).perform(typeText("a123456789"), ViewActions.closeSoftKeyboard())
//輸入密碼
onView(withId(R.id.password)).perform(typeText("a111111111"), ViewActions.closeSoftKeyboard())
...
}

把輸入帳號及密碼擷取方法,這裡其實我們只要知道輸入的帳密是要可以通過檢查的,細節我們應該將其封裝起來。

@Test
fun rightPassword_should_startActivity() {
//輸入正確的帳密
inputRightRegisterData()
...
}

同樣的,將註冊失敗的測試裡的輸入錯誤帳密的部分,重構為一個function。

@Test
fun wrongPassword_should_alert() {
inputWrongRegisterData() ...
}

其他驗證的方式

  • text is:檢查文字內容是否是該文字
  • exists:檢查View元件是存在於於螢幕可見的View中。
  • does not exist:檢查View元件是不存在於於螢幕可見的View中。

Record Espresso Test 錄測試

你還可以使用錄制的方式來產生測試程式碼。

Run > Record Espresso Test

選擇要測試的裝置,可以在模擬器或實體裝置。

在下圖右邊的模擬器直接操作App,左邊就會依照你在App做了哪些動作,錄制下結果。

接著要驗證是否有出現「註冊成功」的字,點擊Add Assertion

點選一下右邊的「註冊成功」,左下角就會出現建議的驗證方式。

點選OK,儲存測試類別。這樣就可以透過錄制的方式來產生測試程式碼

錄好測試程式,也請記得測試程式碼也是要重構的,把測試程式碼當為Production Code的一部分。
Espesso的錄制功能其實還是有些問題,像是錄制時模擬器及錄制都很慢,也會有些測試情境是無法用錄制的。大部分時候你直接寫測試程式還是比較快。建議可以把UI測試的錄制拿來當作在初學時如何取得畫面元件的方式來學習。

範例下載:
https://github.com/evanchen76/uitestsample

參考:
https://developer.android.com/training/testing/espresso

Android TDD 系列
下一篇:13 使用Robolectric 撰寫 Android test

--

--