[GTAC][2014] Espresso, Spoon, Wiremock, Oh my!

這個場次由 Michael Bailey 分享 American Express 內部所採用的 Android 測試架構 (stack)。

撇開所採用的 testing framework – Espresso + Spoon 不談,這個 stack 的特別之處在於它把測試的焦點擺在 app 本身,巧妙地利用 WireMock 將 end-to-end testing 中相對難控制的變因 backend services 給隔離 (isolate) 開來。

espresso-spoon-wiremock-oh-my/stack_replaced.png
圖 1. 測試的焦點 (資料來源: GTAC 2014: Espresso, Spoon, Wiremock, Oh my! – YouTube)

 

講者一開始列出了許多 Android testing tools/frameworks,包括 Calabash (基於 Robotium)、Appium (基於 uiautomatorSelendroid) 與 Espresso。

espresso-spoon-wiremock-oh-my/test_tools.png
圖 2. Android 測試有多種選擇 (資料來源: GTAC 2014: Espresso, Spoon, Wiremock, Oh my! – YouTube)

 

值得注意的是,API 18 增加了 android.app.Instrumentation#getUiAutomation(),透過 UiAutomation 可以讓 instrumentation tests 跨過 app boundaries,不再被侷限在只能操作單一個 app。

Tip Robolectric 在這裡及其他 Google 主講的場次都有被提及,不過它主要是讓 unit tests 能夠執行在傳統的 JVM,而不需要被綁在相對慢的 emulators/devices 上,跟 end-to-end testing 比較沒有關係。

Espresso 基本上是在 instrumentation tests 上做擴充 (會被包裝成為 test APK 的一部份),讓 test code 更容易撰寫。除了提供 fluent API 之外 (這攸關 readability/maintainability),最重要的是它幫忙處理掉了 main UI thread 跟 instrumentation thread 之間的 synchronization。

espresso-spoon-wiremock-oh-my/threads_sync.png
圖 3. Threads 間的 synchronization 是許多 flakiness 的來源 (資料來源: GTAC 2014: Espresso, Spoon, Wiremock, Oh my! – YouTube)

 

另外講者建議用 GoogleInstrumentationTestRunner 來取代內建的 InstrumentationTestRunner,可以減少一些 flakiness。

由於是 instrumentation tests 的關係 (相對於 uiautomator 的做法而言),搭配 Spoon 就可以輕鬆將測試同時撒到多個不同的 devices 上,並產生方便比較不同 device 上測試結果的報表,過程中產生的 device logs、screenshots 也都會被蒐集起來。(官方線上範例

espresso-spoon-wiremock-oh-my/spoon_report.png
圖 4. 一次看到不同 devices 上的測試結果 (資料來源: Spoon Sample App)

 

這個 stack 的最後一塊拼圖則是 WireMock,可以把它想成是一個 “可程式化" 的 proxy,坐落在 app 與 backend services 之間,讓我們可以從 test code 裡動態安排接下來往 backend services 的 requests 要有什麼反應,例如回應特定的資料組合 (combination)、錯誤、延遲一段時間等。

espresso-spoon-wiremock-oh-my/wiremock_features.png
圖 5. WireMock 的使用範例 (資料來源: GTAC 2014: Espresso, Spoon, Wiremock, Oh my! – YouTube)

 

替換 (fake out) 掉 network services 的做法稱之為 hermetic test,這個概念在 Move Fast & Don’t Break Things (Keynote)Fire Away Sooner And Faster With MSL! 都有被提及,除了可以提昇測試的效率,更重要的是可以避開許多 networking 造成的 flakiness。

espresso-spoon-wiremock-oh-my/hermetic_test.png
圖 6. Hermetic Test (資料來源: Move Fast & Don’t Break Things (Keynote))

 

跟 unit tests 裡 mocking 的概念一樣,這裡只是把測試的單元從 class 放大到整個 app 而已 – 假造其他 dependencies 的反應,讓我們可以專心在 app 自身的測試。在實務上,確實有些狀況不好模擬或觸發,尤其 account-based app 會更難處理,因為要事先安排處於特定狀態的 test accounts,考量如果狀態發生變化要怎麼 reset 等。

不過,雖然透過 WireMock 相對容易假造各種狀況下 server 該有的回應,但如何確保這些假造的 test data 不會失真,也就是如何確保當 client 接上真的 backend services 時也能正常運作?類似的問題在 Move Fast & Don’t Break Things (Keynote) 的 Q&A 有被問到,講者 Ankit Mehta (Google) 的答覆是 “three tests, one real and two of the other fake",大概的意思是說大部份的測試為了求快會採 hermetic/fake tests,但同時間也要有一些真正整合 dependencies (backend services) 的 real tests 來確保某些在 hermetic/fake test 裡所做的假設依然成立。

基本上,hermetic test 就是一種 trade-off,要在 move fast 跟 don’t break things 中間取得一個平衡。仔細想想,在 integration test 層級做 mocking 的動作也沒那麼不切實際,更何況不同型態的測試之間本來就是互補的關係,把它定位成 client-side integration test 也未嘗不可。

espresso-spoon-wiremock-oh-my/client_side_integration_test.png
圖 7. 在 Fire Away Sooner And Faster With MSL! 裡將這種專注在 client 端測試並將 server 隔離開來的做法稱做 client-side integration test。 (其中 MSL Server 的角色就像這裡的 WireMock)

 

整體而言,這個 stack 主要的兩個亮點是整合 Spoon 跟 WireMock,至於採用 Espresso 來做 end-to-end testing 這點可能就有些爭議。在 Q&A 有人問到為什麼不採用像 Selendroid 或 Appium 之類的 black-box approach 而選用相對 low-level 的 instrumentation tests,不過講者並沒有正面回答這個問題,只提到這種做法可以從內部檢查 app 的狀態、方便 debug 等,但聽起來就是少了一點說服力。

Tip 雖然 Espresso 的開發看似有點停滯,但作者 Valera Zakharov 在 GTAC 2014: Going Green: Cleaning up the Toxic Mobile Environment 提到 Google 仍繼續在使用 Espresso 做測試。

確實,對照 Make Chrome the best mobile browser 這個場次 Karin Lundberg (Google) 的說法,Chrome 所採用的策略是多一點跑在 Robolectric 上的 unit tests,再用 uiautomator 實作數量相對較少的 end-to-end integration tests,個人覺得這樣的安排比較務實。

espresso-spoon-wiremock-oh-my/chrome_android_strategy.png
圖 8. Chrome for Android 所採用的策略 (資料來源: Make Chrome the best mobile browser)

 

藉由 GTAC 2014 這幾個場次,讓我們重新認識了 hermetic test 在實務上的重要性跟可行性,看來 WireMock 跟 uiautomator (或是基於 uiautomator 的 Appium) 是一個不錯的組合,值得嘗試看看。

廣告

發表迴響

Please log in using one of these methods to post your comment:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s