前面已經做完大部分的單元測試了,現在要開始完成 UI Test 的部分。
UI Test 在 Android 通常被歸類為 Integration Test 的一種,但大家平時很少會寫,加上不知為何 UI Test 有不少奇怪的 bug ,讓門檻變得有些高,所以我今天整理了 UI Test 的幾個重點。
首先是如何進行 UI Test ,一般來說進行 UI 測試的步驟如下:
那麼要如何進那麼要如何進行呢? Android 提供了 Espresso 方便我們開發,在測試篇的第一章我們已經使用 gradle import Espresso 了,所以下面就直接看看 Espresso 如何使用。
前幾天可能忘記提到,由於我們得專案已經使用 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
}
當我們使用 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 被銷毀,接著 User 重新開啟 Activity 時會重新恢復 Activity ,當遇到這種情況可以使用 recreate()
:
class SampleUITest {
@Test fun testEvent() {
val scenario = launchActivity<TasksActivity>()
scenario?.recreate()
}
}
那如果有一個 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)
}
}
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 的測試。