(轉載:http://tmq.qq.com/2016/05/robotium_for_app_test/)html
1 背景目的
應用寶項目組採用FT(Feature Team)模式,整個項目組分爲多個FT,而每一個FT又同時有多個需求分支在並行運做着,幾乎天天都有多新特性合入主幹,項目節奏快、變動頻繁,且又但願可以短週期內快速地對外發布新版本,作到快速交付、持續交付。
爲了支撐項目組的這種研發模式,測試側須要在FT分支上及主幹上作大量的測試,而其中在FT分支的rebase測試、合流後驗證、主幹灰度測試等等階段還包括大量的重複性測試,所以有必要在這些環節加入自動化測試,以持續驗證新特性未破壞原有系統。java
2 框架選擇android
如表1所示,對比了目前業界經常使用的幾個可用於Android端的自動化測試框架:git
經過對比能夠發現不一樣的測試框架各有優缺點,且基本都不能獨自知足全部的測試場景,正所謂菜刀、牛刀、剪刀、指甲刀,刀刀皆有本身的用途與適用場景,咱們須要根據項目狀況及實際的使用場景來選擇最適用的工具。Robotium基於原生Android Instrumentation擴展而來,所以基於Robotium的測試既可使用Robotium自己的API,還可使用Android原生的豐富API,可擴展性更強,且基於Robotium的測試在執行速度、穩定性上有必定優點,而應用寶在手機端只有Android版本,也沒有跨平臺的需求,綜合考慮,所以選擇了Robotium框架。github
3 環境搭建
3.1 基礎環境搭建
測試工程使用了Robotium,採用了的是Android Junit工程,所以須要搭建基礎的Android開發環境,包含JDK、Android SDK、Eclipse + ADT插件 + SVN插件等等開發工具,具體可搜「Android開發環境搭建」搭建基礎環境。
3.2 導入測試工程
1.使用Eclipse導入項目
2.配置Build Path
3.配置keystore
在實際項目中,若是是自家的項目,顯然是不但願對被測App進行重簽名的,有以下緣由:
1)每日進行測試的包衆多,一一進行重簽名影響效率
2)如微信、應用寶等應用作了簽名防禦措施,重簽名後將致使應用部分功能不可用甚至直接沒法啓動
測試工程須要與被測工程簽名一致,所以測試工程須要將keystore配置成應用寶的簽名。Window——Preferences——Android——Build,如圖1所示,點擊Browser,選擇應用寶的debug.keystore簽名,配置完成後,用Eclipse調試時,測試工程打出的apk便是應用寶的簽名了,能夠測試應用寶對外發布的任何包。web
4.配置編碼
新導入工程後,工程可能有許多紅點,此時工程任意有註釋的java文件,若是註釋爲亂碼則是由於編碼不一致致使。此時須要將工程編碼設置爲utf-8。也可右鍵選擇測試工程,僅設置該工程爲UTF-8編碼。
3.3 Eclipse設置
工欲善其事,必先利其器,測試工程使用Eclipse做爲IDE,而爲了編寫代碼能夠更高效,有必要進行一些提升效率的設置。
1.配置輸入聯想
爲了提升測試用例的代碼編寫效率,頗有必要配置輸入聯想,在Eclipse中Preferences——Java——Editor——Content Assist配置輸入聯想chrome
其中Auto activation triggers for java中默認只有.符號,即輸入.時纔會有代碼聯想出來,爲了充分利用代碼聯想功能,須要在該輸入框中把abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ這26個字母及.號輸進去,這樣,當鍵入.號或26個字母時,就會有自動提示,提升代碼輸入效率。
2.配置Eclipse的JVM參數
Eclipse的JVM默認設置參數較小,所以可能形成各類卡慢現像,而咱們的開發機配置通常較高,能夠經過調整JVM參數充分利用機器資源提升Eclipse運行的流暢度,修改Eclipse安裝目錄下的eclipse.ini文件便可,具體可參考以下配置(修改-vmargs參數後面的配置):
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms2048M
-Xmx2048M
-Xmn656M
-XX:PermSize=512M
-XX:MaxPermSize=1024M
-XX:+UseParallelGC
-XX:CMSInitiatingOccupancyFraction=85
-Xverify:none
-Xnoclassgc
-XX:+CMSClassUnloadingEnabled
-XX:+CMSPermGenSweepingEnabled
-XX:+DisableExplicitGC
3.關聯源碼
a)關聯內引用jar包的源碼
導入測試工程後,libs下的Robotium和Uiautomator兩個jar使用了properties配置,默認就已關聯上了sources目錄下的源碼,如圖3所示:shell
b)關聯外引用jar包的源碼
關聯外引用jar包的源碼,這裏主要關聯Android SDK中的源碼,右鍵android.jar,進入Java Source Attachment選項,關聯sdk中的源碼,如圖4所示:數據庫
至此,不論進入的是Android SDK仍是Robotium中的class類,都可以查看到其源碼實現。
4 Robotium
4.1 Robotium介紹
Robotium對外主要提供如下幾個類:瀏覽器
By: //Web元素的選擇器
Condition: //接口類,用於等待
RobotiumUtils: //工具類
Solo: //對外提供各類API
Solo.Config: //Solo配置類
SystemUtils: //系統級工具類
TimeOut: //Solo配置類
WebElement: //Web元素的抽象類
其中Solo類是主要對外提供各類API的類,Solo類採用中介者模式,持有com.robotium.solo包下的其它類的的實例對象,當咱們調用Solo類中的API時,實則大多數是轉而調用com.robotium.solo包下其它類的方法。com.robotium.solo包下主要有如下類:
Getter: //提供控件獲取相關API
ActivityUtils: //提供Activity相關API
Asserter: //提供斷言相關的API
Clicker: //提供模擬點擊相關的API
ScreenshotTaker: //提供截圖相關的API
Scroller: //提供滾動相關的API
Searcher: //提供控件搜索相關的API
ViewFetcher: //提供控件過濾相關的API
Waiter: //提供控件等待相關的API
WebUtils: //提供Web支持相關的API
Robotium爲了簡化測試用例的編寫,將以上的這些類都置爲了protected,對外只提供Solo類,所以,在編寫測試用例時,主要實例化Solo類便可
Robotium爲一款支持黑盒測試也支持白盒測試的自動化測試框架,簡單易用,提供了獲取控件、發送點擊事件、斷言等等API。
主要API如表2所示:
經過如上API文檔也能夠發現,Robotium框架提供的API是有限的,且也只是使用了一小部分Android的API封裝而成。使用Android、Java豐富的類庫咱們能夠開發出微信、手Q、應用寶等等衆多App,一樣地,咱們也可使用這些豐富的類庫去擴展測試框架。
所以,選擇Robotium測試框架,不僅是選擇的一個測試框架,而是選擇的一種測試模式,即基於Android、基於Junit的測試模式。
4.2 Native控件獲取與處理
1.uiautomatorviewer
可使用%ANDROID_HOME%\tools目錄下的uiautomatorviewer.bat工具直接獲取當前界面的控件結構及其id。
注:uiautomatorviewer只有在Android較高版本(4.3及以上)才能直接獲取控件id值。
2.處理惟一id的控件
若是當前界面該控件id是惟一的,則處理起來很簡單,以下:
Button loginBtn = (Button) solo.getView(「loginBtn」);
solo.clickOnView(loginBtn)
3.處理id相同的控件
在Android中,列表ListView採用的是Adapter形式,因此列表中的控件id都是相同的。
此時,須要先獲取節點控件的父視圖,經過父視圖再查找相應的子視圖。
4.控件過濾
測試過程當中最多見的方式就是控件過濾
API:getCurrentViews(Class classToFilterBy, View parent)
例如想獲取某一個區域內的全部文本:
ArrayList textViews = holo.getCurrentViews(TextView.class,parentView);
其中parentView爲父視圖,獲取parentView下全部的TextView
4.3 WebView控件獲取與處理
WebElement元素獲取能夠經過Chrome Mobile Emulation模式獲取。安裝有較新版本Chrome瀏覽器,按F12便可進入Chrome Mobile Emulation模式。
輸入H5頁面連接,如:http://xxx.xxx.xxx/index.html
如圖6所示能夠看到’電視劇’擁有class=」classify classify-tv」的惟一屬性。
對於有些沒法經過PC瀏覽器打開的H5頁面,能夠經過Chrome DevTools鏈接手機端直接進行調試。
使用DevTools須要如下前置條件:
1.PC端須要安裝Chrome 32及以上版本
2.USB線鏈接手機設備
3.用於browser debugging:須要Android4.0及以上版本,並安裝有Chrome Android版本
4.用於app debugging:須要Android4.4及以上版本,並將WebView設置爲可調試
須要注意的是,PC端中的Chrome版本須要高於手機端中的Chrome版本。
App中將WebView設置爲可調試,可以使用以下代碼設置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
DevTools詳情介紹可參見官網:
https://developer.chrome.com/devtools/docs/remote-debugging#reverse-port-forwarding
而後,在Chrome瀏覽器地址欄中輸入「chrome://inspect/#devices」
打開應用寶,進入含有WebView的頁面,例如進入娛樂TAB,如圖7所示,能夠看到出現了能夠inspect的頁面,點擊’inspect‘按鈕便可對該頁面進行調試,如圖8所示,展現了該頁面的元素。
知道了元素的屬性後,便可調用相應API獲取WebElement對象,經過By方式獲取:getCurrentTxWebElements(By by);By方式支持經過classname、id、textcontent等方式,如:
holo.getCurrentTxWebElements(By.className(className));
獲取到了相應的WebElement對象後,便可對Web元素進行操做:
clickOnWebElement(By by)
clickOnWebElement(WebElement webElement)
waitForTxWebElement(By by,int timeout,boolean scroll)
4.4 斷言
1.Assert中的斷言
使用junit.framework.Assert包中的斷言:斷言條件的true或false、是否爲空等等。如圖9所示:
2.ViewAsserts中的斷言
使用android.test.ViewAsserts包中的斷言:包括斷言控件是否左對齊、右對齊、父視圖是否包含某子視圖等等。
5 跨應用(結合UiAutomator2.0)
2015年3月Android Developers團隊宣佈了UiAutomator 2.0版本的發佈,這個版本最重要的就是UiAutomator終於能夠基於Instrumentation了,使用Instrumentation test runner便可運行UiAutomator,反過來,也即在基於Instrumentation的test中也能使用UiAutomator。所以測試工程可同時使用Robotium和UiAutomator進行更豐富地測試。
新版的UiAutomator隨Android Support Repository發佈,可經過SDK Manager下載,以2.1.0版本爲例,位於以下所示的路徑中:
%ANDROID_HOME%\extras\android\m2repository\com\android\support\test\uiautomator\uiautomator-v18\2.1.0
新的測試支持庫基本都是基於Android Studio庫,文件以aar結尾而非jar結尾,本小節爲方便在Eclipse中介紹須要將aar轉化成jar。如圖11所示,使用壓縮工具打開uiautomator-v18-2.1.0.aar文件,裏面的classes.jar文件便是可用於Eclipse的UiAutomator jar包。提取出該classes.jar文件並重命名爲方便記憶的jar包文件,導入至使用了Robotium的測試工程便可。
如圖12所示,應用寶在通知欄中開啓了快捷工具欄,測試此功能時須要開啓通知欄,並點擊工具欄中的按鈕,這樣的操做僅經過Robotium框架是沒法完成的,此時就能夠結合UiAutomator來實現。
UiAutomator發佈2.0版本後,能夠經過傳入Instrumentation對象得到UiDevice對象。
UiDevice.getInstance(instrumentation);經過UiDevice對象能夠完成點擊Home鍵、打開通知欄,並經過UiDevice的findObject方法能夠根據文本、資源id等等查找控件,並經過UiObject對象完成點擊操做。
使用的findObject方法獲得的爲UiObject對象,此外也能夠經過By的方式獲取UiAutomator中的UiObject2對象,例如:
uiDevice.findObject(By.res(「com.tencent.android.qqdownloader」, 「entry_text_1」)).click();
UiAutomator2.0還有許多更豐富更強大的功能,這裏就再也不一一介紹,總之,經過與Instrumentation結合能夠方便地在測試工程中完成跨應用的操做,進行更豐富地測試。
6 測試工程
6.1 測試工程概覽
使用Robotium進行自動化測試,測試工程爲一個Android Junit Test工程,能夠依賴被測工程,與能夠選擇獨立存在。
關聯被測工程源碼的好處在於能夠調用被測工程的代碼,所以能夠更容易地獲取到被測應用內部的狀態,例如拿到被測應用ListView內部填充的數據等等。而這樣也會帶來一些弊端:
1.測試工程的自動化編譯打包也須要關聯被測工程,腳本複雜度及維護成本增長
2.若是採用R.id.xxx方式獲取控件的話,被測工程增長、刪除佈局文件均可能影響到測試工程的編譯結果
3.若是被測應用進行了代碼混淆,引用被測工程的代碼複雜度將大大提升
鑑於此,應用寶採用的是脫離被測工程的方式,同一份測試apk能夠同時測試多個版本的被測應用,另外,即便你們選擇有源碼的方式,也不建議使用R.id.xxx的方式獲取控件。
測試工程須要在AndroidManifest.xml文件中註冊instrumentation用於指定被測應用:
instrumentation android:targetPackage="com.robotium.android.notepad" android:name="android.test.InstrumentationTestRunner"
在同一個測試工程中咱們能夠只註冊一個instrumentation,也能夠同時註冊多個,例如當被測應用有多個,而測試工程又不想分別創建多個時,則可使用註冊多個的方法。首先,先編寫一個繼承自android.test.InstrumentationTestRunner的自定義InstrumentationTestRunner,而後一樣地在AndroidManifest.xml中註冊:
instrumentation android:targetPackage="com.robotium.android.anothernotepad" android:name=".instrumentation.InstrumentationTestRunner"
6.2 測試用例
6.2.1 測試用例生命週期
測試用例基於Android Junit,每一個用例遵循如下三個步驟:
1)首先,執行setUp()方法,用於初始化。
2)而後,執行以public且方法名以test開頭的用例方法。
3)最後,執行tearDown()方法,用於釋放資源等
另外,因爲許多用例都須要擁有一樣的功能特色,例如須要可以進行出錯重試與出錯截圖等等,所以,能夠編寫一個共有的測試基類,應用寶測試工程中全部的測試類均繼承自SingleLaunchActivityTestCase2這個類。
6.2.2 測試用例編寫
測試用例編寫的質量直接關係到用例的穩定性、維護成本以及是否能發現有效問題等等,所以是自動化測試中的關鍵一環。
首先,是肯定測試用例的來源。
當開始準備編寫自動化測試用例時,須要肯定測試用例的來源,即須要明確例如如下幾個方面:
哪些功能是主要功能、哪些功能能夠自動化
用例的優先級、做用的測試階段
測試一個功能須要哪些驗證點
不一樣的項目組須要思考的點可能不同,但目的是一致的,須要明確測試用例的來源,而不是任意地開始編寫用例。應用寶中採用CheckList的形式,經過與各業務線討論評審的方式肯定關鍵功能、是否自動化、用例優先級、測試驗證點等等。
而後,應該合理地去設計自動化測試用例
在設計自動化測試用例時,除了實現用例來源中的功能步驟外,用例的原子性是須要額外注意的,這將影響到多個用例在一塊兒時是否能夠高效穩定地運行。用例的原子性,即指用例間應該保持相對獨立,不因用例執行的前後順序而彼此幹攏。
此外,應該以工程的視角去看待測試用例
測試代碼也應該以工程的視角去看待,包括配置管理、結構管理、項目化運做等等。在編寫測試用例過程當中也應該儘量地從工程角度在代碼易用性、維護性方面去多加考慮。測試代碼也應該要有代碼規範,包含命名規範、編寫規範、註釋規範等等,以使測試用例能高效有質量地運轉起來。
最後,應該驗證測試用例的有效性
自動化測試用例自己也是須要通過驗證與測試的,一個測試用例自己運行經過了並不必定表明用例就是有效的。例如可能由於檢查點判斷有問題致使該用例始終經過,而通常當用例開始交付運行後,若是一直是經過的,那麼每每就不會有人關注,且測試人員會認爲該模塊已經有自動化測試去保障從而容易忽略基本的測試,因此經常無效的自動化測試用例比沒有自動化測試更可怕,須要警戒出現無效的測試用例。在編寫測試用例時須要驗證用例的有效性,在測試用例交付使用後,也應該按期地關注測試用例的運行狀況及其有效性。
6.2.3 測試用例執行
1. 傳統命令行執行方式
(1)Running all tests:
adb shell am instrument -w com.tencent.assistant.qa/android.test.InstrumentationTestRunner
(2)Running a single testcase:
adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.nuclear.MobileAccelerateTest com.tencent.assistant.qa/android.test.InstrumentationTestRunner
(3)Running a single test:
adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.nuclear.MobileAccelerateTest#testMgr_MobileAccelerate com.tencent.assistant.qa/android.test.InstrumentationTestRunner
(4)Running multiple tests:
adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.pangu.FoundTabActivityTest,com.tencent.assistant.qa.testcase.nuclear.AssistantTabActivityTest com.tencent.assistant.qa/android.test.InstrumentationTestRunner
2.使用spoon執行
java -jar spoon-runner-1.1.3-SNAPSHOT-jar-with-dependencies.jar \
–apk example-app.apk \
–test-apk example-tests.apk \
–class-name com.tencent.assistant.qa.testcase.common.SearchTest
3. 在Eclipse中執行
選擇一個測試類後,右鍵Run As —— Android Junit Test執行便可
注:在Run Configuration中,如設置有多個Instrumentation runner,則須要指定InstrumentationRunner,如圖13所示:
6.2.4 測試用例管理
當編寫了較多測試用例時,就須要將測試用例分類管理起來,以方便統一維護及用例分級。基於Junit的測試可使用TestSuite的方式進行管理。
因爲在測試執行時,不一樣的用例執行時間長短不一樣,且做用的測試階段也各不相同階,所以在進行用例管理時,須要明確用例的級別,例如區分是核心功能用例仍是普通用例,從而將不一樣級別的用例放於一處進行管理,在執行時才能夠有針對性地進行測試。
6.3 測試報告
6.3.1 Spoon報告
Spoon是一個由主導有okhttp、retrofit、leakcanary等衆多優秀開源項目的Square公司在GitHub上的開源項目,志力於改善基於Instrumentation的測試。經過分佈式地在多臺手機上同時執行基於Instrumentation的測試用例,而且在測試完成後生成統一的擁有測試結果概覽、截圖、運行時日誌等等功能的HTML形式測試報告,Spoon能夠更加快速有效地對Android終端進行自動化測試。
項目開源地址:https://github.com/square/spoon
測試採用的Spoon生成,生成報告如圖14所示,其中綠條表示用例經過,紅條表示用例失敗:
點擊紅條可跳轉至失敗用例的報告詳情頁,如圖15所示:
用例採用出錯重試並截圖機制,當用例失敗時進行截圖,並日後開啓截取一系列運行時的圖片,每一個用例右邊有四個按鈕,分別爲將截圖以gif格式播放、展現多臺手機下同一用例運行狀況、運行時日誌查看、javadoc文檔連接。
例如點擊右3按鈕查看運行時日誌,如圖16所示:
6.3.2 歷史數據聚合報告
Spoon會相似單元測試形式的XML報告文件,所以其餘測試平臺能夠經過解析junit-reports目錄下的XML報告獲取用例執行的詳情數據,對每次的測試進行入庫存儲,積累平常的測試數據,生成歷史記錄的測試報告頁面。
7 持續集成
7.1 Jenkins介紹
Jenkins,原名Hudson,2011年改成如今的名字,它是一個開源的實現持續集成的軟件工具。官方網站:http://jenkins-ci.org/。
Jenkins 能實施監控集成中存在的錯誤,提供詳細的日誌文件和提醒功能,還能用圖表的形式形象地展現項目構建的趨勢和穩定性。
7.1.1 參數化構建
Jenkins支持多種參數化構建,如圖18所示:
7.1.2 構建前
構建前可關聯SVN,設置定時觸發器等等常規操做。
此外,安裝相應插件後,構建前也能夠刪除workspace中的指定文件、設置當超時的時候是否中止構建、向workspace事先拷貝文件等等操做
7.1.3 構建
構建能夠增長如圖19所示的諸多構建步驟:
經常使用的有Execute shell(在Linux機器中執行時),用於執行shell腳本
Execute Windows batch command(在Windows機器中執行時),用於執行bat批處理腳本
7.1.4 構建後
構建後能夠選擇如圖20所示的構建後步驟,經常使用的有郵件發送、觸發新的構建任務、傳遞參數等等功能。
7.2 總體流程圖
由7.1節可知,Jenkins支持參數化構建、關聯SVN、能設定觸發時機、支持執行Shell或bat腳本、支持執行後郵件反饋、支持分佈式運行等等一系列持續集成的流程。且Jenkins包含豐富的插件能夠用於擴展功能,結合實際項目,所以應用寶使用Jenkins來作自化測試的持續集成,總體流程如圖21所示。
BVT自動化測試根據不一樣的分支支持定時觸發、分支監控及手動上傳三種方式觸發測試。任務建立後,將根據所選擇的測試節點執行測試,測試用例採用基於Robotium框架編寫,測試執行採用基於Spoon框架執行,所以支持在單臺手機上執行也支持同時在多臺手機上同時執行。測試執行完成後數據報告將回傳服務端進行數據處理,數據處理完成將在相應平臺上展現數據報告並郵件反饋相關負責人。
定時觸發:用於主幹每日夜裏執行全量用例
分支監控:用於監控DB分支,當DB分支有新的構建時,就拉取相應apk進行BVT測試
手動上傳:支持各FT及發佈分支手動上傳apk文件,手動觸發BVT測試
任務建立:任務建立時會將測試工程進行編譯打包生成測試.apk,並會將測試工程中須要用到地腳本文件、jar包插件等統一拷貝至服務端的一個根據job名稱命名的臨時目錄。
執行測試:在執行測試前,會將服務端該臨時目錄下的全部文件push至Slave執行機,而後執行相應的初始化腳本,例如卸載安裝應用、清理手機中的殘留數據等。
數據處理:在執行測試完成後,執行相應腳本,從手機中pull出測試產物,例如代碼覆蓋率用的ec文件、性能監控數據、協議日誌數據、內存快照文件等。而後使用相應的jar包插件解析測試報告、上傳數據至數據庫等操做。
郵件反饋:調用郵件模版將測試報告發送指定的收件人。在這種模式下,BVT測試支持自動執行也支持手動觸發執行,在Jenkins中以模版形式既可較靈活地進行配置,且配置維護也較爲容易。另外任意能鏈接成爲Jenkins節點的PC均可以迅速成爲節點PC機,在節點PC上掛上手機便可成爲系統的一部分,能夠執行BVT自動化測試任務。