中文翻譯版:ios
爲了使你們確信「應作單元測試,就必定能作單元測試」,谷歌測試工程師Mona El Mahdy專門寫了一篇博客,提出了幾種執行安卓應用用戶界面單元測試的方法。Mahdy推薦使用 Robolectric和Android Studio Gradle插件作常規的單元測試,用 Espresso 或 UI Automator 建立和運行單元測試。後端
端到端的測試。Mahdy提出的第一種UI測試方法是E2E。這樣的測試應該能夠啓動安卓應用及其全部與之相關的後端系統,使之能夠在真實的場景中完成UI測試。重複執行這些的測試是很困難的,由於「存在不少的影響因素,好比網絡帶寬、實際服務器的認證、系統規模等」,因此就很難作到「E2E測試的調試排查和穩定化處理」。爲簡化這些點,Mahdy也提出了一些其餘的測試策略。服務器
用隔離的服務器測試。隔離的服務器是指與外界隔離的服務器,是在本地運行的一臺單獨的服務器,不鏈接網絡。在運行的時間經過依賴注入(可能須要綁定到這臺服務器的靜態文件)的方式提供與其餘服務器的鏈接,若是須要的話,還能夠在本地文件或內存存儲中僞造一些響應數據。另外一個選擇是,爲隔離的服務器提供一系列記錄好的響應,以模擬真實終端服務器的返回值。markdown
針對測試目的,隔離的服務器做爲被測系統在同一臺機器上本地運行,其上運行安卓模擬器。雖然這種方式提升了測試的執行速度,有時也會消除一些網絡鏈接的碎片,可是它須要單獨的集成測試以確保客戶端應用與後端是同步的。出於這個目的,Google+團隊用了一組「黃金的」需求/響應文件,你們都知道它們包含了客戶端應用到終端服務器的正確的傳輸序列。用黃金的需求文件根據這臺服務器的全部響應生成一個文件,而後再用這個文件與黃金的響應文件進行比較。網絡
Mahdy提出,使用隔離的服務器比E2E測試能夠更好地完成測試,可是調試卻仍舊是個難題,並且這臺隔離的服務器可能會致使一些通信碎片。因此,她提出了另外一個改進方案。app
使用依賴注入(DI)。移動應用能夠設計成支持依賴注入的,在測試期間有些模塊能夠用仿造模塊代替。應用將和仿造的網絡模塊進行通信,這個網絡模塊爲全部請求提供應答,以取代剛纔所講的使用網絡模塊的隔離的服務器。這會使UI測試更快更可靠。在DI這一方面,Mahdy建議使用Dagger。ide
多重類庫。若是安卓應用比較大,Mahdy建議把它分割成更多小的組件,每一個和它本身的模塊和視圖把包到一個單獨的類庫中。而後,大家就可使用單獨的DI、模擬模塊和測試進行每一個組件的開發和測試了。爲確保整個應用的運轉,須要集成的測試。這一方式更是進一步提高了測試的速度。組件化
最後,Mahdy總結道:「組件化的UI測試要比E2E測試快得多,並具有99%的穩定性。快速而穩定的測試從根本上提高了開發人員的生產效率。」post
英文原文版:單元測試
Convinced that 「whatever can be unit tested should be unit tested」, Mona El Mahdy, a Software Engineer in Test at Google, has written a blog post proposing several approaches to perform unit tests on the user interface of Android applications. Mahdy recommends Robolectric and the Android Studio Gradle plug-in for general unit testing, and Espresso or UI Automator for creating and running UI tests.
End-to-End (E2E) Tests. The first approach to UI testing mentioned by Mahdy is E2E. Such a test should be able to fire up the Android application and all its related back-end systems, enabling the UI testing in real life scenarios. Repeatedly performing such tests is difficult because 「debugging and stabilizing E2E tests」 is hard due to 「many variables like network flakiness, authentication against real servers, size of your system, etc.」 To simplify things a bit, Mahdy proposes another strategy for testing.
Testing using Hermetic Servers. Hermetic servers are servers that are isolated from the outside world, running locally on a single machine without network connections. Connections to other servers are provided at runtime through dependency injection, any static files that might be requested are bundled with the server, and, if necessary, responses to data store requests are faked with data from local files or an in-memory store. Another option is for a hermetic server to provide a sequence of responses recorded when returned by a real back-end server.
For testing purposes, hermetic servers run locally on the same machine as the System Under Test (SUT) where the Android emulator runs. While this approach speeds up test runs and eliminates flakiness sometimes associated with network connections, it requires separate integration testing to make sure the client app is in sync with the back-end. For this purpose, the Google+ team uses a pair of 「golden」 request/response files that are known to contain a correct sequence of transmissions between a client app and a back-end server. The golden request file is played and a file is created with all the responses coming from the server, being later compared with the golden response file.
Mahdy argues that using hermetic servers is better for testing than E2E tests, but debugging is still not easy and the hermetic server may cause some flakiness in communication. So, she proposes another improvement.
Using Dependency Injection (DI). The mobile application can be designed for using DI having some modules replaced with faked ones during testing. Instead of talking to a hermetic server through a network module, the app will communicate with a fake network module which provides answers to all requests. This makes UI tests even faster and reliable. For DI, Mahdy suggests using Dagger.
Multiple Libraries. When an Android application is larger Mahdy suggest splitting it up into smaller components each with its own module and view packaged in a separate library. Then, each component can be developed and tested using separate DI, fake modules and tests. Integration tests are necessary to make sure the entire app works. This approach speeds up testing even further.
At the end, Mahdy concludes: 「Componentized UI tests have proven to be much faster than E2E and 99%+ stable. Fast and stable tests have proven to drastically improve developer productivity.」