Robotium是一個開源的androidUI自動
測試工具,這里不做介紹,可以見:http://code.google.com/p/robotium/
Orange:
Orange 是我們自己開發的運行在PC端的(只支持windows),用于組織
測試用例、自動重簽名apk文件、以及操作模擬器、啟動運行測試用例、用 例crash以及失敗重跑、測試結果收集等功能的一個工具,通過簡單的配置,既可以全自動全SDK版本回歸運行robotium編寫的測試用例。
為什么開發Orange?
為什么要自己開發一個Orange工具,而不直接使用Robotium編寫的測試代碼來運行測試用例?
我們在Robotium測試用例運行的過程中發現了以下的一些問題:
1、測試用例運行過程中有時候會直接Crash,導致所有測試用例停止,同時收集不到測試結果
2、用例在模擬器上運行,用例經常會出現失敗的情況, 但是你再次運行的時候可能就用成功了,存在不穩定性
另外我們希望有下面的功能:
1、我們希望用戶編寫好以及robotium的測試用例后,能夠方便的全自動全SDK版本回歸運行測試用例
2、我們希望用戶能夠方便的指定當前運行哪些測試用例
3、我們希望能夠得到一個直觀的運行結果報告
當前這里最重要的是在使用Robotium發現的問題,如果你的用例在運行時crash了,導致什么結果也收集不到, 如果你的自動測試用例穩定性太低,經常出現大量的失敗用例,那么用戶如何來相信你的測試結果,大量失敗用例你去分析失敗原因也是一個非常耗時的過程,如果 不能很好的解決穩定性的問題,搭建的自動測試框架失敗率會大大的提高。
Orange使用步驟:
為了更好的生成測試結果報告,我們這里使用了一個開源的軟件android-junit-report,官方地址:https://github.com/jsankey/android-junit-report ,該軟件繼承重寫了
android自帶的InstrumentationTestRunner,會自動把測試結果生成到xml文件中。
所以基于Robotium編寫測試用例的時候需要額外的進行下面的兩部操作:
1、從https://github.com/jsankey/android-junit-report下載jar包,同時加入到測試用例程序中
2、修改測試程序的AndroidMainifest.xml文件,在文件中加入以下配置
<instrumentation android:targetPackage="com.netease.pris(被測應用的包名)" android:name="com.zutubi.android.junitreport.JUnitReportTestRunner" /
接下去就可以開始編寫測試用例了,測試用例編寫完成后,
1、獲取到被測應用的apk文件,以及你的測試程序的apk文件
2、填寫orange框架的配置文件,有一些指定的必填配置項
該文件主要是填寫需要測試的sdk版本、被測應用的apk位置、被測應用的主包名、測試程序的apk位置、測試結果收件人列表、測試用例的xml文件地址
config.properties
#填寫需要測試的android sdk版本,多個的話中間用逗號隔開,不允許為空
target=android-10,android-14
#
被測試應用存放的位置,windows下目錄之間用"\\"來分割,不允許為空
apkpath=D:\\PRIS\\1.3.1\\pris_generic_1.3.1.apk
# 測試程序存放的位置,windows下目錄之間用"\\"來分割,不允許為空
testapkpath=D:\\PRIS\\1.3.1\\PrisUIAutoTest.apk
#
測試程序的主包名,不允許為空 package=com.netease.pris
# 運行結果的收件人列表,多個用戶用逗號分割,允許為空 maillists=***@163.com,***@163.com
# 測試用例的配置文件絕對路徑,不允許為空 testCaseFile=D:\\TestCaseInfo.xml
3、編寫指定需要運行的測試用例文件
這里類似于testng的方式來指定需要運行哪些測試用例,但是為了解決crash以及失敗重跑的問題,只支持每個測試方法單獨配置,而不支持只填寫到測試類級別。
TestCaseInfo.xml
<!-- packageName 填寫的是測試程序的主包名,必填項 -->
<classes packageName="com.netease.mobile.autotest">
<!--
指定需要運行的測試類,這些類是在測試程序中編寫的,也會安裝到模擬器中-->
<class name="com.netease.mobile.autotest.testing.PersonalDataTest" >
<methods>
<!--
這里定義需要運行的具體測試方法,這些都是必填項,如果不存在會報錯-->
<include name="test01ShowPersonalData" /> <include name="test02EditPersonalData" /> </methods> </class> </classes> |
4、如何運行測試程序
orange框架會生成一個jar包,當你配置好這些選項后,并且拿到了orange.jar后,直接運行命令
java -jar Orange.jar D: \\config.properties
則orange框架會開始自動為測試應用以及被測應用重簽名,按照配置項,創建、啟動模擬器、安裝apk文件、運行測試用例(crash自動重啟模擬器,失敗則自動重跑,當前最多跑三次),測試用例運行完成后收集測試結果,發送到指定的收件人。
Orange實現原理:
1.1 自動重簽名APK文件
使用Robotium來測試應用的話,需要測試程序和被測程序的簽名是一樣的,但是一般被測程序都會有自己簽名過,所以我們需要實現自動的刪除被測程序以及測試程序的簽名文件,然后使用統一的key對被測程序的測試程序進行簽名。
實現原理:
1、刪除apk文件中的META-INF文件夾
使用winrar工具的 winrar d ***.apk META-INF 命令可以實現在不解壓apk文件的情況下刪除壓縮包內指定文件夾
所以這里需要先下載安裝winrar工具,另外在電腦的環境變量中配置winrar的安裝目錄,保證在cmd命令中能夠調用到winrar命令
(PS:這里原來是使用的java jar -xvf 命令先把apk解壓縮,然后調用刪除方法刪除掉META-INF,最后使用jar -cvf壓縮為apk文件,但是通過jar命令解壓縮之后,重簽名后的網易閱讀apk會出現崩潰的情況,改成了通過winrar工具來實現)
2、使用JARSIGNER命令對apk文件使用統一的key進行重簽名操作
3、使用zipalign命令對重簽名后的文件進行優化
Orange框架如何使用bat腳本:
1、bat腳本和重簽名的key在Orange的jar包中會保存一份
2、運行Orange時,復制bat文件、key文件以及測試應用和被測試應用到temp目錄下
3、通過java方法的Process process = Runtime.getRuntime().exec( "cmd.exe /c start " + path); 執行bat文件
4、bat文件會自動把當前目錄下的apk文件全部都進行重簽名,重簽名的apk文件保存到指定目錄下
1.2 自動創建、啟動、刪除模擬器以及安裝apk功能
需要在不同sdk版本的模擬器上實現全自動切換運行測試用例,所以需要涉及到創建、啟動、刪除模擬器以及安裝apk文件等功能。
實現原理:
所有這些操作都使用了android自帶的android命令來實現的
1、創建模擬器 android create avd --name OrangeAutoTest --target android-7 --force
通過java中調用以上命令實現創建模擬器的操作,如何判斷創建模擬器的是否成功,以及失敗的話錯誤信息呢?
Process process = Runtime.getRuntime().exec(cmd);來執行上面的cmd命令行
然后通過process.getInputStream() 和process.getErrorStream()來獲取到相應的返回信息,如果有錯誤信息的話可以再getErrorStream中獲取到
說明: 正確情況下getErrorStream能夠獲取到值的話則拋出異常說明命令執行是時候出錯了,但是有些命令的話執行正常,但是getErrorStream也能獲取到返回值,所以有些命令需要做特殊的處理。
2、啟動模擬器 emulator -avd OrangeAutoTest -sdcard c:\sdcard.img
通過上面的命令啟動模擬器,同時加載sdcard,sdcard可以通過mksdcard 20M c:\sdcard.img命令來創建
3、刪除模擬器android delete avd -n OrangeAutoTest
4、安裝APK adb wait-for-device install -r *.apk
1.3 Crash以及失敗用例重跑功能
平時我們使用Robotium編寫完一些測試用例的時候經常是直接通過Eclipse運行多個測試用例,或者通過junit編寫一個testsuite把需要運行的測試用例加入到testsuite中一次運行多個測試用例。
但是在運行的過程中,我們會發現有時候應用會Crash,導致的結果是測試暫停,所有測試的結果都收集不到。
另外在運行的時候因為模擬器的一些不穩定性,可能會存在某一次用例運行失敗的情況,但是再次運行用例就恢復正常了。
為了解決Crash的問題,以及失敗用例重跑的問題,我們開發了運行在PC端Orange框架。
實現原理:
1、運行測試用例的時候通過Orange框架控制每次只運行一個測試用例,這樣子如果這一個用例運行crash了或者失敗的話,我可以再次啟動應用重新運行,對其它用例不會有影響。
首先通過Robotium編寫的需要運行的測試用例需要配置在xml文件中,按照類似TestNG配置文件的格式來指定這次運行哪些測試用例
<!-- packageName is required--> <classes packageName="com.netease.mobile.autotest"> <class name="com.netease.mobile.autotest.testing.LoginTest"> <methods> <include name="testLogin" /> <include name="testUnLogin" /> </methods> </class> </classes> |
這里要求配置的時候必須配置到具體的方法,我們運行的時候Orange框架會解析這個xml文件,最后組合成以下的一些命令來循環運行測試用例,每次運行一個
adb shell am instrument -e class com.netease.mobile.autotest.testing.LoginTest#testLogin -w com.netease.mobile.autotest/com.zutubi.android.junitreport.JUnitReportTestRunner
adb shell am instrument -e class com.netease.mobile.autotest.testing.LoginTest#testUnLogin -w com.netease.mobile.autotest/com.zutubi.android.junitreport.JUnitReportTestRunner
2、如何判斷用例是運行Crash的?
我們還是通過Process process = Runtime.getRuntime().exec(cmd);方法來運行第一步生成的adb命令,然后通過 process.getInputStream();獲取到流的返回值,如果返回值中包含"shortMsg=Process crashed"字符的話,說明這個用例運行crash了,那我們使用重試機制
再次運行這個測試用例,如果連續3次都是crash的話,則把crash的信息也寫入到返回值中,保證了用例運行Crash的話也能夠收集的錯誤信息。
3、如果判斷用例運行失敗?
這里使用了JUnitReportTestRunner的一個開源的插件(https://github.com/jsankey/android-junit-report),是重寫了官方的InstrumentTestRunner,能夠幫我們收集每個用例的執行情況。
每次用例執行結束后,會在模擬器或者真機的指定位置下生成一個Junit-report.xml文件,我們通過adb pull 命令把這個文件保存到PC端,然后Orange框架來解析這個文件,如果結果中包含failure或者error的話說明這個用例運行失敗了,則重跑用 例。
如果不包含的話說明用例運行成功,則把剛才取出的xml文件存下來,后續所有用例運行完成整合為一個完整的xml結果文件。
4、如何實現用例重跑?
這個只需要實現一個方法的遞歸調用就可以,每次運行的時候會查看返回值以及解析xml的返回結果文件,如果存在異常則遞歸調用該方法,同時會定義一個運行次數的參數,如果大于這個次數的時候不管是夠通過都會保存當前最后一次的運行結果。
//調用運行測試用例方法 result = e.run(testCase, testAppPackageName); // 如果出現timeout異常則再運行一次 if (result.equals(EmulatorHelper.timeOutException)) { //如果超出運行次數,則保存錯誤信息,否則遞歸運行 if(j > runCount){ addErrorToXml(root, testCase, "adb shell am timeoutexception", beginTime,"TimeOutException"); return result; }else{ return runTest(root, e, testCase, testAppPackageName,appPackageName, j); } |
1.4 測試結果收集功能
每次運行一個用例結束的時候,會把當前用例的運行結果加入到xml的節點中,所有用例運行結束后,xml文件會保存在PC端的指定位置下。
收集到的測試結果樣式如下:
<?xml version="1.0" encoding="UTF-8"?> <testsuites> <testsuite name="com.netease.mobile.autotest.testing.LoginTest"> <testcase classname="com.netease.mobile.autotest.testing.LoginTest" name="testUnLogin" time="59.499"/> </testsuite> <testsuite name="com.netease.mobile.autotest.testing.SubscribeTest"> <testcase classname="com.netease.mobile.autotest.testing.SubscribeTest" name="testAdd2" time="74.099"> <failure message="junit.framework.AssertionFailedError: Button with the text: 取消訂閱 is not found!" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: Button with the text: 取消訂閱 is not found! at com.jayway.android.robotium.solo.Clicker.clickOn(Clicker.java:324) at com.jayway.android.robotium.solo.Solo.clickOnButton(Solo.java:684) at com.netease.mobile.autotest.common.PrisOperation.addSubscribe(PrisOperation.java:91) at com.netease.mobile.autotest.testing.SubscribeTest.testAdd2(SubscribeTest.java:126)</failure> </testcase> </testsuite> </testsuites> |
1.5 測試報告生成功能
首先會獲取到收集的測試結果xml文件,然后解析xml同時加入一些css樣式,生成html文件,郵件中發送的正文內容就是html文件內容。
這里就是一個解析xml以及樣式處理的過程。