iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 12
2
Mobile Development

Android TDD 測試驅動開發系列 第 12

Day12 - UI 測試:使用Espresso

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

在指定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

https://ithelp.ithome.com.tw/upload/images/20190926/20111896QElIqgscjq.png

在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測試的方式一樣是按綠色的三角型,就可以看到模擬器被開起來自動測試。

https://ithelp.ithome.com.tw/upload/images/20190926/20111896icdiShC7mo.png

success

註冊失敗也是需要測試的。註冊失敗需要驗證是否有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()))
}

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

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

@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

https://ithelp.ithome.com.tw/upload/images/20190926/20111896b2RiUyACW9.png

選擇要測試的裝置,可以在模擬器或實體裝置。
https://ithelp.ithome.com.tw/upload/images/20190926/20111896AStJC4ILii.png

在下圖右邊的模擬器直接操作App,左邊就會依照你在App做了哪些動作,錄制下結果。
https://ithelp.ithome.com.tw/upload/images/20190926/20111896iKaRVD1SSB.png

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

點選一下右邊的「註冊成功」,左下角就會出現建議的驗證方式。
https://ithelp.ithome.com.tw/upload/images/20190926/20111896sxzHfafB5v.png

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

https://ithelp.ithome.com.tw/upload/images/20190926/20111896v1tVly1h3Z.png

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

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

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

出版書:

Android TDD 測試驅動開發:從 UnitTest、TDD 到 DevOps 實踐


上一篇
Day11 - Instrumented Tests
下一篇
Day13 - 使用Robolectric 撰寫 Android test
系列文
Android TDD 測試驅動開發30

1 則留言

0
神威
iT邦新手 2 級 ‧ 2020-07-31 12:08:02

evanchen 大大好:
最近在試著寫Espresso,有些問題不知是否能請教您?
我APP有有2個頁面A和B
我打算先試最簡單的
我在A輸入數字,按button會轉跳B(這裡我有做到
到B頁面輸入一串字串(也OK
按手機返回建,返回A頁面(這裡就不行....
以下是我的程式,能麻煩大大指點一下嗎?,謝謝

public void mainActivityTest() {
   //main.java
    onView(withId(R.id.acc2)).perform(typeText("2"),closeSoftKeyboard());
    onView(withText("login")).perform(click());
   //now is second.java
    onView(withId(R.id.name)).perform(typeText("john"));
  //I hope I can back to main.java but fail....
    pressBack();
    //onView(isRoot()).perform(ViewActions.pressBack());
    onView(withId(R.id.acc2)).perform(typeText("5"), closeSoftKeyboard());
}

我要留言

立即登入留言