打造方便單元測試的 LifecycleOwner

邱懷民
一個被音樂耽誤的Android工程師
5 min readMar 7, 2020

前言

今天要跟大家分享如何打造一個方便做單元測試的 LifecycleOwner ✌️

未完成的網路請求有沒有在 onDestroy() 的時候取消呢?

想讓這個頁面在 onResume() 的時候刷新,該怎麼驗證?

如果你常煩惱著這些問題,是時候為自己的程式碼加上 Lifecycle 相關的單元測試了!除了確保功能有在正確的 Lifecycle 上面執行以外,也可以幫助你(或同事)在未來不會弄壞你寫的功能 😬

如果你還對測試 Lifecycle 沒有頭緒,又或是在猶豫要不要跨出第一步的話,請讓小弟我為您提供一些方向 🙈

今天就來針對上面這兩種情形做為範例,跟大家介紹一下如何用簡單的幾行程式碼來撰寫單元測試。

Step1. 寫個能手動控制 Lifecycle state 的工具

在開始之前,大家需要先瞭解下面這兩個 Lifecycle 相關的 class 👇

LifecycleOwner、LifecycleRegistry

簡而言之,LifecycleOwner 就是個用來提供 Lifecycle 的 interface ,而 LifecycleResgistry 則是可以幫你控管 Lifecycle 一切狀態的 class,需要提供 lifecycle 來初始這個類別。

瞭解了這兩個 class 之後,我們就可以寫出主要功能了,先附上程式碼

看起來是不是很簡潔呢?

我們讓 ManualLifecycleOwner 繼承 LifecycleOwner,然後再宣告 LifecycleRegistry 用來提供 Lifecycle 給這個 class。接著再宣告一個 state 變數並提供 getter 和 setter 方便我們做使用。

TL;DR. 有興趣的人可以參考看看 ComponentActivity,裡面對 Lifecycle 的實作也是一樣的原理

Step2. 加上方便初始化的 Builder function

有了功能之後,來寫方便在單元測試中宣告的 builder function 吧!這邊提供大家兩個初始化的情境,在單元測試中應該就非常夠用了。

1. 需要初始 Lifecycle state,後續要隨著需求變更 state

2. 只需要固定的 Lifecycle state,後續測試不需要更動 state

Tips: 可以設成 private constructor 避免繞過 builder function 直接建立

Step3. 開始寫測試拉 🎉

最後就來針對前言提到的兩個情境進行單元測試拉!

1. 未完成的網路請求有沒有在 onDestroy() 的時候取消呢?

@Test
fun `cancel request when activity destroyed`() {
val lifecycleOwner = ManualLifecycleOwner.withState(CREATED)
val model = MyViewModel(lifecycle = lifecycleOwner.lifecycle)
val disposable = model.requestSomething()
lifecycleOwner.state = DESTROYED

assert(disposable.isDisposed())
}

2. 想讓這個頁面在 onResume() 的時候刷新,該怎麼驗證?

@Test
fun `refresh page when activity resumed`() {
val lifecycleOwner = ManualLifecycleOwner.withState(CREATED)
val model = MyViewModel(lifecycle = lifecycleOwner.lifecycle)
// Make sure page doesn't refresh when started
lifecycleOwner.state = STARTED
verify(exactly = 0) { model.refreshPage() }

lifecycleOwner.state = RESUMED
verify(exactly = 1) { model.refreshPage() }
}

小結

其實在 Android 釋出 Jetpack Components 之後,寫 code 的方式比以前直觀,要控制 Lifecycle 和 Lifecycle-aware components 也變得容易許多。從以前剛接觸 Android 被 Lifecycle 搞得團團轉,到現在能夠有清晰的方式掌握並撰寫測試,真的還滿開心的 🎉

目前小弟正在努力學習 Android 相關技術,偶爾會寫寫文章練練文筆,有錯誤或是能改進的地方都歡迎大大們留言指教!

最後,希望這篇文章能幫助到需要的開發者們,謝謝大家 🙌

--

--

邱懷民
一個被音樂耽誤的Android工程師

喜歡抱著吉他彈彈唱唱,夢想是靠著寫程式改變世界。