iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
0
自我挑戰組

Android Architecture 及 Unit Test系列 第 23

[Day 23] Test:Part 5 UI Test

  • 分享至 

  • xImage
  •  

前面已經做完大部分的單元測試了,現在要開始完成 UI Test 的部分。

UI Test 在 Android 通常被歸類為 Integration Test 的一種,但大家平時很少會寫,加上不知為何 UI Test 有不少奇怪的 bug ,讓門檻變得有些高,所以我今天整理了 UI Test 的幾個重點。

首先是如何進行 UI Test ,一般來說進行 UI 測試的步驟如下:

  • 搜尋元素 (元件)
  • 觸發動作
  • 驗證結果

那麼要如何進那麼要如何進行呢? Android 提供了 Espresso 方便我們開發,在測試篇的第一章我們已經使用 gradle import Espresso 了,所以下面就直接看看 Espresso 如何使用。

寫第一個 UI Test

前幾天可能忘記提到,由於我們得專案已經使用 Android X ,所以需要在 app build.gradle 的android.defaultConfig 裡指定新的 TestRunner

    testInstrumentationRunner androidx.test.runner.AndroidJUnitRunner

再來先在 androidTest 建立新的測試,由於 UI Test 是在真正的 View 上跑的,所以準備寫測試前,需要先讓 Activity 在測試前啟動。

Android X 提供了 ActivityScenario 這個 API 來啟動和驅動 Activity 的生命週期以進行測試,可以寫一個方法獲得 ActivityScenario

    private fun launchActivity(): ActivityScenario<TasksActivity>? {
        val activityScenario = launch(MainActivity::class.java)
        return activityScenario
    }

改變 Activity 的生命狀態

當我們使用 launch 方法獲得 ActivityScenario 時,此時 Activity 的初始狀態是 State.RESUMED ,所對應的即是 Activity 的 Resume 狀態,如果要把 Activity 的生命週期切換到其他的狀態,可以使用 moveToState()

class SampleUITest {
    @Test fun testEvent() {
        val scenario = launchActivity<TasksActivity>()
        // 將 Activity 狀態切成 onCreate
        scenario?.moveToState(State.CREATED)
    }
}

重新恢復 Activity

有時候因為記憶體不足或是旋轉畫面等造成 Activity 被銷毀,接著 User 重新開啟 Activity 時會重新恢復 Activity ,當遇到這種情況可以使用 recreate()

class SampleUITest {
    @Test fun testEvent() {
        val scenario = launchActivity<TasksActivity>()
        scenario?.recreate()
    }
}

接收 Activity result

那如果有一個 Activty 呼叫了他自己的 finish() ,這時要怎麼驗證呢?

ActivityScenario 提供 getResult() 讓我們可以得到 Activity 的 result 結果,這樣就可以去驗證這個狀態來確保 Activity 被 finish :

class SampleUITest {
    @Test fun testEvent() {
        val scenario = launchActivity<TasksActivity>()
        // UI Test 點擊一個 finish 按鈕
        onView(withId(R.id.finishButton)).perform(click())
        assertThat(scenario.result,resultCode).isEqualTo(Activity.RESULT_OK)
    }
}

執行 Activity 自己的方法

ActivityScenario 另外提供了 onActivity 讓我們可以控制 Activity 自己的方法:

class SampleUITest {

    ......
    private fun launchActivity(): ActivityScenario<TasksActivity>? {
        val activityScenario = launch(MainActivity::class.java)
        activityScenario.onActivity { activity ->
        
            // activity.onBackPressed() 、 activity.applicationContext ...
            ......
        }
        return activityScenario
    }
}

最後我們來完成一個測試:

@RunWith(AndroidJUnit4::class)
class SampleFragmentTest {
    @Test
    fun checkHelloWorldIsDisplayed() {
    
        launchActivity()
        onView(withText("Hello world")).check(matches(isDisplayed()))
    }
}

結語

現在 Espresso 的功能日趨完善,再搭配 ActivityScenario (還有本次沒提的 FragmentScenario) 讓寫 UI test 變得十分簡單,但是他也有他自己的問題,但至少今天已經把大致上的使用方式都介紹一遍了。

如果後面幾天還有時間可能會再更深入介紹,不過今天就先這樣,
明天開始完成 Fragment 的測試。


上一篇
[Day 22] Test:Part 4 UseCase and ViewModel
下一篇
[Day 24] Test:Part 6 Fragment
系列文
Android Architecture 及 Unit Test30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言