1. 程式人生 > >【騰訊TMQ】【測試左移專欄】用Powermock和Mockito來做安卓單元測試

【騰訊TMQ】【測試左移專欄】用Powermock和Mockito來做安卓單元測試

作者:ZeusL

團隊:騰訊移動品質中心TMQ

一、單元測試及Android單元測試簡介

慣例,先簡單介紹下理論知識,懂得的可以跳過。

1、單元測試定義和特性

單測定義:

在計算機程式設計中,單元測試(Unit Testing)又稱為模組測試, 是針對程式模組(軟體設計的最小單位)來進行正確性檢驗的測試工作。
程式單元是應用的最小可測試部件。在過程化程式設計中,一個單元就是單個程式、函式、過程等;對於面向物件程式設計,最小單元就是方法,包括基類(超類)、抽象類、或者派生類(子類)中的方法。

單測特性:

擷取下《單元測試的藝術》一書中的優秀的單元測試特性,牢記!

2、Android單元測試

顧名思義,是在Android系統下進行的單元測試。

業界上已經有很多工具可以支援做Android系統下的單元測試,主要分為兩大類:

(1)Instrumentation

通過Android系統的Instrumentation測試框架,我們可以編寫測試程式碼,並且打包成APK,執行在Android手機上。

優點: 逼真;

缺點: 很慢;

代表框架:Junit,Espresso。

(2)Junit / Mock

通過Junit,以及第三方測試框架,我們可以編寫測試程式碼,生成class檔案,直接執行在JVM虛擬機器中。

優點: 很快,使用簡單,方便;

缺點: 不夠逼真,比如有些硬體相關的問題,無法通過這些測試出來;

代表框架: Junit,Robolectric, Mockito, Powermock。

Robolectric:一個單元測試框架,可以清除Android SDK(通過shadow技術),以便您可以測試驅動Android應用程式的開發,測試JVM內部執行,用例執行速度很快。

Espresso:一種簡潔,美觀,可靠的Android UI測試框架。

Mockito:一個針對 Java 的單元測試模擬框架,它與 EasyMock 和 jMock 很相似,都是為了簡化單元測試過程中測試上下文 ( 或者稱之為測試驅動函式以及樁函式 ) 的搭建而開發的工具。

Powermock:是在 EasyMock 以及 Mockito 基礎上的擴充套件,通過定製類載入器等技術,實現了之前提到的所有Mockito不能模擬的功能,比如靜態函式、建構函式、私有函式、Final 函式以及系統函式的模擬。

二、Google官方MVP架構

在熟悉單元測試框架前,首先需要學習了下Google官方推薦Android的MVP專案架構,好的框架單元測試也比較好開展。

其推薦的專案中MVP各層所使用的單元測試框架如下圖所示:

其MVP測試架構圖總結如下:

專案程式碼有興趣學習的同學可以去自行下載去學習,學習這種優秀程式碼是最快的方式。

View層:

職責:MVP模式下,View本身該做的事情都能做了,比如UI佈局,資料渲染,點選按鈕互動等等。

測試方式:以正常小QA的測試思維方法,就可以來定義這一層的測試方式,測試過程中需要真機或模擬器,並做真實的操作。

測試選型:依賴於Android環境,用谷歌強大的Espresso+AndroidJunitRunner,Espresso用於模擬和驗證各種各樣的UI操作,程式碼存放於AndroidTest中。

Presenter層:

職責:這一層是拉皮條的,負責M和V層的對接,所以有較少的處理輸入輸出的機會,他只用來控制邏輯,去呼叫相應的Model和View的邏輯。

測試選型:他的職責決定了他很少去斷言輸入輸出,測試邏輯覆蓋的路徑是否正確即可,因此他與Android環境無關,用Junit+Mockito測試即可,程式碼存放於test中。

Model層:

職責:負責資料的存取,資料可能來自於網路、資料庫和記憶體。

資料庫增刪改查:需測試資料存取的準確性,依賴Android環境進行測試,因此使用AndroidJunitRunner,程式碼存放於AndroidTest中。

網路請求:不測試真實的網路請求,但提供了Fake供其他層呼叫測試。

封裝的門面類:決定了資料的來源和去向是來自於本地資料庫 or 網路 or 記憶體,此為真正對其他層暴露的Model類。此類不做資料準確性的驗證,只做mock測試,驗證覆蓋路徑。UT選型Junit+Mockito,程式碼存放於test中。

MVP各個模組通訊方式如下:

除了MVP,還有一種MVC的方式。

MVC的全稱為Model-View-Controller,即模型-檢視-控制器。

Model:處理資料和業務邏輯等。

View:顯示介面,展示結果等。

Controller:控制流程,處理互動。

MVC各個模組通訊方式如下:

MVC和MVP區別:

在MVC模式中,View和Model可以直接互動;在MVP模式中,View和Model模組不能直接互動,View通過Presenter與Model間接互動。

在MVC中,Controller是基於行為的,可以被多個View共享,可以負責決定顯示哪個View;在MVP中View和Presenter是一對一或這一對多的,並且Presenter和View是通過介面互動的。

三、單元測試環境一些基本的準備工作

1、新建一個標準的Android Studio工程

新建一個andriod Studio工程,這個就不詳細說明了,網上有很多教程。

成功後src目錄下就出現AndroidTest和test下目錄。

2、原始碼和其他工程目錄搬遷移植

將原始碼目錄全部放在src/main/java下(適合老業務改造)。

如果原始碼目錄指定不對,需要修改build.Gradle的sourceSets配置。

3、增加工具框架依賴

在dependencies下增加工具框架的引用。

注:如果用到什麼框架就將框架引用進來即可,但有些工具主要版本號的相互搭配,不匹配可能會出現錯誤。

網上有一個PowerMock對Mockito的版本對應關係:

作者使用的是下面紅色的組合,請根據實際情況匹配。

4、增加Jacoco覆蓋率

增加Jacoco的外掛:

指定版本號和報告目錄:

指定原始碼目錄。
自定義Jacoco報告規則task:

上面一切準備完畢後,配置好程式碼,Gradle就可以正常同步載入了。

如果你的Android Studio的Gradle Sync同步成功,那麼恭喜你單測環境基本OK了,依賴庫基本也已經下載完畢,下面可以愉快的開始著手程式碼編寫了。

可能有的公司需要網路代理,那這個需要根據具體情況在Gradle中配置了。

四、編寫AndroidTest下的單測用例

UI層的單元測試只簡單介紹一下,作者實際編寫單元測試的時候,UI部分的單元測試用例也是放在了test目錄下一起寫的(PowerMock模擬的),執行不需要手機或模擬器,執行速度比較快。

雖然沒有在實際專案中大量使用,但也將當初的嘗試簡單介紹一下,供參考。

UI的Instrumentation用例可以選取Espresso。

在AndroidTest目錄下新建一個測試類。

比如我們測試一個這樣的單測用例:測試更新頁的點選更新所有,使用者頁面會彈出一個toast確認的彈框。

用例編寫如下:

手機連上電腦,選中用例滑鼠右鍵run就可以執行看結果了。

五、編寫test下的單元測試用例

首先介紹下單測工具框架選取的過程。

1、選取合適的測試框架

作者開始在業務中嘗試使用Robolectric測試框架,初心主要在於他的特性:

Robolectric Test-Drive Your Android Code Running tests on an Android emulator or device is slow! Building, deploying, and launching the app often takes a minute or more. That’s no way to do TDD. There must be a better way.
Wouldn’t it be nice to run your Android tests directly from inside your IDE? Perhaps you’ve tried, and been thwarted by the dreaded java.lang.RuntimeException: Stub!?

它不需要Run你的模擬器,直接在jvm上執行你的測試程式碼,能在短時間之內快速驗證,通過體驗之後,它確實非常高效,編寫測試程式碼反而加速了開發效率。

另外被它強大的Shadows方式所吸引,可以完全實現自定義方式。

但在實際使用的過程中遇到了不少的坑,比如:

Robolectric版本和SDK版本強依賴。

compileSdkVersion 23的不能使用Robolectric:3.0的版本,只能使用Robolectric:3.2.2以上的。為什麼會有這種強依賴,是因為Robolectric會shadow大部分Android的程式碼,會有很多shadow的類,也就會隨sdk版本的變化而變化。

Robolectric首次啟動下載maven相關的依賴失敗。

即使我們在開發網下設定了代理,開通外網許可權,首次啟動還會去下載相關依賴,結果是下載失敗,這個是由於Robolectric本身程式碼裡的邏輯,我們不能通過網路代理的方式解決。

唯一的辦法只能一個一個手工的下載後丟到你的.m2\repository\org\Robolectric目錄下,讓Robolectric找到其所依賴的jar包,不需要在去下載,如下:

如果在build.Gradle重新指定Robolectric的版本,那麼這些需要的版本還要手工下載一遍。

Robolectric執行報TinkerRuntimeException: Tinker Exception:onCreate method not found
業務使用了Tinker多包載入架構,執行出現上面的異常。

解決方法:
RealAstApp裡面人為增加oncreate方法
@Override
public void onCreate() {
}
這樣修改程式碼其實是有點犯忌的,但只改這一處還勉強可以接受,下面的就不能接受了。

Robolectric執行在自定義的控制元件時有時會出現xml解析異常。
跟蹤解決了幾個,發現要修改的地方比較多,這裡省略一萬字的修改記錄。
除了改動點比較多,也可能後續會出現更多的潛在錯誤。
違背上面的單元測試特性之執行穩定,衡量再三,還是決定放棄Robolectric了,另尋它徑。

這裡也宣告下,Robolectric工具還是很優秀的,它的解決思路很清晰,所有呼叫到Android相關的都會轉移到其shadow類,這樣就可以完全脫離Android的限制,只是由於業務的特殊性才暫時不用。

於是又開始研究Espresso,見上面的(編寫AndroidTest單元測試用例)。
使用過程中總體感覺Espresso功能比較強大,只要合理的使用其提供的api和matches規則,常用的UI邏輯基本都可以模擬,但唯一不爽的就是每次都要連線手機或者模擬器才能執行,Run的過程中,首先會打包,部署到手機上,然後再開始一個一個執行測試用例,好處是手機上的表現很直觀,但這樣除錯和執行速度是真心的慢。

違背上面的單元測試特性之執行速度快,建議放棄。

嘗試使用Junit、Mockito和Powermock來編寫MVP三層的單元測試用例,在經過一陣探索後,MVP三層的邏輯基本都可以通過Mockito和Powermock來模擬出來,執行起來關鍵是速度快,速度快,速度快,好的地方說三遍。

上面的單元測試特性也基本都能滿足,最終決定使用Junit、Mockito和Powermock這個框架組合來進行我們的單元測試用例設計和編寫。

2、選取被測模組和熟悉被測模組的程式碼邏輯

在單元測試前要對被測模組有個大致的程式碼邏輯熟悉,對程式碼的深入可以邊寫邊熟悉。

3、PowerMock知識點掌握

單測用例編寫過程中,熟練程度一部分完全取決於對單測工具框架的瞭解程度,這塊沒捷徑可走,必須要掌握清楚明白,簡單列一下其知識點,具體還是需要自己去搜索資料掌握的。

(1)PowerMock註解@RunWith與@PrepareForTest的使用;

(2)測試或模擬static方法;

(3)測試或模擬返回void的靜態方法;

(4)PowerMockito.doNothing與PowerMockito.doThrow的使用;

(5)如何驗證方法呼叫;

(6)如何驗證呼叫次數的方法;

(7)測試或模擬final類或方法;

(8)測試或模擬構造方法;

(9)如何做引數匹配;

(10)Answer介面的使用;

(11)如何使用spy進行部分模擬;

(12)如何測試或模擬私有方法;

(13)@Before和@Test的作用;

(14)如何給私有的欄位賦值;

(15)如何模擬異常。

4、設計單元測試用例

需要寫單測case列表。

在我們的專案中,單元測試物件建議和類相對應,這樣的單元測試結果比較直觀。單元測試分析被測類的業務邏輯,這裡的邏輯不僅僅包括介面元素的展示以及控制元件元件的行為,還包括程式碼的處理邏輯。然後可以建立單元測試case列表,列表用於紀錄專案中單元測試的範圍,便於單元測試的管理以及新人瞭解業務流程,列表中記錄單元測試物件的頁面,物件中的case邏輯以及名稱等,測試或開發工程師可以根據這個列表開始寫單元測試程式碼。

用覆蓋率來校驗單測用例是否完備。

單元測試是工程師程式碼級別的質量保證工程,上述流程並不能完全覆蓋重要的業務邏輯以及邊界條件,因此,需要寫完後,看覆蓋率,找出單元測試中沒有覆蓋到的函式分支條件等,然後繼續補充單元測試case列表,並在單元測試工程程式碼中補上case。

直到被測類所有邏輯的重要分支、邊界條件都被覆蓋,才認為該類的單元測試結束。

另外覺得複用或通用的邏輯建議做成工具類,直接複用。

整理了一個case的單測流程圖,供參考:

5、公共的可複用的抽離出成工具類

將一些常用的場景抽象出工具mock類,如BundleMock、HandlerMock、IntentMock、MainThreadHandler、ParcelMock等等,這樣提供給單測直接呼叫即可,不用在重複造車輪。

6、幾種場景的單元測試用例案例

單元測試用例設計,格式可以自己靈活去定義,另外也可以在程式碼中已Javadoc的方式新增單元測試用例內容,輸入、輸出、斷言幾點明確就可以了。
我們把一部分專案常用的場景通過mock實現後,剩下的基本都是工作量的問題了。

目前業務程式碼邏輯場景的模擬做了如下:

(1)請求的模擬及回撥onRequestSuccessed和onRequestFailed的模擬;

(2)頁面inflate載入場景模擬;

(3)頁面findViewById載入場景模擬;

(4)控制元件onclick場景模擬;

(5)資料回撥場景模擬;

(6)主執行緒handler場景模擬;

(7)序列化的模擬;

(8)intent的模擬;

(9)其他等等。

這部分的模擬程式碼就不貼上來了,有點多,需要可以線下交流。

7、單測類的編寫經驗

(1)mock物件可以被整個類的測試方法共用的,mock時統一放到@Before裡init;

(2)mock物件僅供單個單測用例使用的,mock時可以直接放到單測用例裡;

(3)能抽象出來的mock物件,建議做成工具類呼叫;

(4)單測用例一定要有斷言,且斷言準確,這樣才能保證單測用例的有效性;

(5)不要怕麻煩,開始都會感覺很難,寫多了熟練了就好了。

8、debug除錯

執行時候如何出現一堆黃色的PASSED,心裡當然感覺爽了。

但在單元測試編寫執行中難免會出現各種異常錯誤,mock時出現空指標的場景會比較多,這時候我們就需要用debug除錯方式。

然後設定斷點,通過F8逐步跟蹤下去吧,找出單測用例的編寫的問題所在。

9、生成覆蓋率報告

在Android Studio的Terminal中輸入Gradlew JacocoTestReport後,單元測試開始執行,無錯誤結束後就會在指定的報告生成目錄下看到覆蓋率結果了。

通過覆蓋率結果,檢視到單測case覆蓋情況,根據情況補充或修改單測用例,加大覆蓋率結果的提升,單測是有望達到100%覆蓋的。

單測過程中可能會出現某些類的覆蓋率結果為0的,但實際上應該有覆蓋率的,這可能是由於一些頁面單測場景下被測類在@PrepareForTest中聲明瞭,導致這些類的覆蓋率為0。以前作者也介紹過Jacoco的原理,其是修改class位元組碼檔案插樁的,但再經過PrepareForTest這種指定後,PowerMock也會修改class的位元組碼,這樣就把Jacoco的插樁沖掉了,導致覆蓋率為0,這部分我們可以通過自己寫指令碼的方式來算覆蓋率,然後在和Jacoco的覆蓋率相疊加算出總的覆蓋率。

六、做單測的意義

現在各個專案的程式碼量都比較龐大,全部進行單測覆蓋,工作量消耗是非常巨大的。

並且產出和收益也不一定成正比例。

其實我們做單測和做系統測試的出發點都是一樣的,提升專案的總體質量。

兩點實施方式:

1、對於開發久,穩定的功能,單測的出發點為系統功能測試的互補。

單測的著重點在功能測試難覆蓋的地方,通過單測發現功能測試難發現的問題及程式碼潛在的問題。

2、對應剛開發,新功能,如果有時間和人力的話,可以考慮單測全覆蓋。

儘量在開發編碼時並行實施,或者推動開發自己寫單測。

最後有一個話題有機會大家可以一起討論下:

單測的投入和產出如何來平衡?

獲取更多測試相關乾貨 請關注我們的微信公眾號——騰訊移動品質中心TMQ:

這裡寫圖片描述

相關推薦

TMQ測試專欄PowermockMockito單元測試

作者:ZeusL 團隊:騰訊移動品質中心TMQ 一、單元測試及Android單元測試簡介 慣例,先簡單介紹下理論知識,懂得的可以跳過。 1、單元測試定義和特性 單測定義: 在計算機程式設計中,單元測試(Unit Testing)又稱為模組測試,

TMQ這樣的測試過程管理讓你事半功倍

導語 相信每一位測試小夥伴對於測試過程管理都有自己的獨特見解。我所在的部門2017年初開始施行測試變革——“測試左移”。過程中有從技術層面的”左移“,也有從流程層面的”左移“等等,方式形態萬千。今天和大家分享的是我在這個過程中,除了個人技術能力提升外,在測試過

TMQ從0開始後臺測試

從使用者反饋說起 “我備份的照片怎麼不見了”; “出現伺服器錯誤-1001”; “下載的照片無法顯示”。 使用者反饋,測試過程中經常遇到各種與後臺相關的非必現問題,對於一個重後臺功能的產品,包括很多業務邏輯和使用者的資料都與後臺強相關,若只是通過客戶端來

TMQGoogle是如何Chrome瀏覽器的效能測試的?

導語 近期研究了一下chrome的強大的效能測試工具telemetry,收穫頗豐,現簡單介紹一下telemetry的測試框架。telemetry中的很多方法都正在逐步的引入到自研的桌面QQ瀏覽器效能自動化測試系統中。 一、概述 Telemetry是一套

TMQ遠端移動測試平臺對比分析

作者:趙麗娜 隨著移動裝置和系統的碎片化程度越來越高以及複雜的行動網路情況, 相容性測試以及遠端真機測試的重要性越來越突出。根據遠端測試機/人員與開發者間的合作方式,可以分為以下幾種服務:雲測試服務、內測服務以及眾測服務,相應的平臺支援如下圖。 雲

TMQUTP自動化測試平臺系列之三例管理

導語 UTP自動化測試平臺是TMQ的一個聯合專案,目的是方便各專案測試人員更好地開展自動化測試建設工作,減少重複平臺建設的成本,提高產品的自動化測試效率。 背景 測試用例,是測試的基礎原料,沒有用例,測試工作無法執行,自動化測試也是一樣。實際的自動化測

TMQ測試管理平臺大比拼

作者:solinazhao 簡介 測試管理平臺是貫穿測試整個生命週期的工具集合,它主要解決的是測試過程中團隊協作的問題,比如缺陷管理、用例管理、測試任務管理等。 目前市面上比較流行的測試管理工具有QC、 Mantis、 BugZilla、TestL

TMQ如何輕鬆爬取網頁資料

一、引言 在實際工作中,難免會遇到從網頁爬取資料資訊的需求,如:從微軟官網上爬取最新發布的系統版本。很明顯這是個網頁爬蟲的工作,所謂網頁爬蟲,就是需要模擬瀏覽器,向網路伺服器傳送請求以便將網路資源從網路流中讀取出來,儲存到本地,並對這些資訊做些簡單提取,將我們

TMQ再不建模你就out了

導語 加入測試建模小組八個多月的時間,在日常的測試工作中,經常會有身邊的小夥伴們對我們的建模很好奇,會問“什麼是測試建模?”“為什麼要測試建模?”“建模能給我們帶來什麼好處?”“建模和我們現在的測試設計區別到底在哪裡?“等等諸如此類的問題。思來想去,實在有必要

TMQJAVA程式碼覆蓋率工具JaCoCo-踩坑篇

作者:劉洋 一、覆蓋率踩過的坑 在專案中使用JaCoCo覆蓋率的時候,也遇到過各種奇葩的問題,在這裡列出來分享下,問題和實際的專案關係密切,希望對有遇到過相似問題的童鞋有所啟發。 1.1 覆蓋率包在部分手機6.0上安裝失敗 事情起因:在測試新功

TMQTTS評測--方案介紹實踐分享

導讀 語音合成(Text To Speech,TTS)技術將文字轉化為聲音,目前廣泛應用於語音助手、智慧音箱、地圖導航等場景。TTS的實現涉及到語言學、語音學的諸多複雜知識,因合成技術的區別,不同的TTS系統在準確性、自然度、清晰度、還原度等方面也有著不一樣的

使用Powermockmockito進行單元測試

簡介 Mockito是一個流行的Mocking框架。它使用起來簡單,學習成本很低,而且具 有非常簡潔的API,測試程式碼的可讀性很高。因此它十分受歡迎,使用者群越來越 多,很多的開源的軟體也選擇了Mockito。 要想了解更多有關Mockito的資訊,請訪問它的官方網站:h

Spring Boot 2 實踐記錄之 使用 PowermockMockito 對 UUID 進行 mock 單元測試

alt 生成 digest md5 加密 調用 uuid tid 第一步 加密算 由於註冊時,需要對輸入的密碼進行加密,使用到了 UUID、sha1、md 等算法。在單元測試時,使用到了 Powermock,記錄如下。 先看下加密算法: import org.apache

【騰訊優測】騰訊優測是備受客戶信賴的移動雲測試平臺,為應用、遊戲,H5混合應用的研發團隊提供產品質量檢測與問題解決服務。不僅在線上平臺提供「全面相容測試」、「原始碼缺陷分析」、「遠端真機租用」等多種質量檢測工具

騰訊優測 騰訊優測是備受客戶信賴的移動雲測試平臺,為應用、遊戲,H5混合應用的研發團隊提供產品質量檢測與問題解決服務。不僅在線上平臺提供「全面相容測試」、「原始碼缺陷分析」、「遠端真機租用」等多種質量檢測工具...

Bugly乾貨分享移動網際網路測試到質量的轉變

Dev Club 是一個交流移動開發技術,結交朋友,擴充套件人脈的社群,成員都是經過稽核的移動開發工程師。每週都會舉行嘉賓分享,話題討論等活動。 本期,我們邀請了 TesterHome 測試技術社群聯合創始人“陳曄”,為大家分享《移動網際網路測試到質量的轉

bugly幹貨分享精神哥手把手教你怎樣智鬥ANR

waiting pen nag 技術分享 input 這就是 max-width 卡死 gravity 上帝說要有ANR,於是Bugly就有了ANR上報。那麽ANR究竟是什麽? 近期非常多童鞋問起精神哥ANR的問題,那麽這次就來聊一下,雞爪怎麽泡才好吃。噢不,是怎

CVM的功能優勢學習總結

騰訊雲 騰訊雲的功能 騰訊雲的特點 騰訊雲的功能與優勢具有以下幾個方面:提供全面的服務彈性的雲端CVM的管理平臺可靠CVM極速的CVM性能多種解決方案來保證CVM和數據的安全簡單易用多種計費模式,降低IT投入成本騰訊雲CVM提供了全方面的服務內容,具體為以下幾類:實現了多region多zone覆蓋

敏捷轉型No.4 為什麽敏捷團隊不要超過15人

領導 原創 規模 數據 scrum 評審 是否 php 開發 早期,騰訊公司的架構是比較簡單的。從上至下分別是:公司——商業單元(BU)——部門——組——員工,每個部門基本上就是負責一個大的產品,每個組都是按照專業進行分工和管理,例如:產品組、終端組、後臺組、設計組、運維組

敏捷轉型No.7QQ郵箱如何通過敏捷成為行業第一

使用 界面 討論 模式 但是 詳細 自然 都是 target 前幾篇文章講到2006年的騰訊是如何開始敏捷轉型的,接下來這篇文章,我將向大家講述,騰訊開始敏捷轉型之後,QQ郵箱是如何通過敏捷成為行業第一。 眾所周知,張小龍是“微信之父”,對他熟悉的人,應該也知道

微信紅包

題目描述 春節期間小明使用微信收到很多個紅包,非常開心。在檢視領取紅包記錄時發現,某個紅包金額出現的次數超過了紅包總數的一半。請幫小明找到該紅包金額。寫出具體演算法思路和程式碼實現,要求演算法儘可能高效。 給定一個紅包的金額陣列gifts及它的大小n,請返回所求紅包的金額。 若沒有金額超