在Android平台上,如果要實施自動化測試的話,有幾個方式,比如使用基於Instrumentation類庫及其衍生類,或者是使用monkeyrunner,測試案例運行在PC上,通過USB或者WIFI向Android手機的應用發送測試命令。這兩個方案各有優缺點:
1、 Instrumentation技術的優點是編寫UI自動化測試案例的技術跟編寫Android應用的技術是同一個技術,而且API也是使用Android本身的類庫。但是它的缺點是需要待測應用使用調試用密鑰進行數位簽章,這是因為Android平台強制要求一個應用如果要讀取或者修改另外一個應用的狀態的話,必須是同一個實體,而同一個實體的證據就是使用同一個密鑰進行數位簽章。因此使用Instrumentation技術來測試第三方應用的話,就必須先將第三方應用的數位簽章去掉,重新使用調試版密鑰簽名才能執行測試。如果應用裡有資源檔需要使用原先的數位簽章才能解密的話,那麼啟動重新簽名過的應用時,就會出現問題。例如QQ的Android版就是這種情況,重新簽名後,再啟動就會崩潰
– 從預防他人惡意複用智慧財產權的角度來說,是一個非常好的做法,但對於自動化測試就是另一種情況了。
2、 Monkeyrunner的缺點是,只能運行在PC機上,其運作原理是測試案例是在PC機上解釋用例指令碼,通過網路向Android手機的應用發送訊息實現的。如果要求只能在手機上,完全脫離PC機的話,就沒辦法測試。例如要在實際測試電訊廠商的網速和通訊品質,測試人員可以拿市面上幾個流行的應用,寫幾個自動化測試案例,然後手持手機裝置執行測試。
曾經碰到類似的測試需求,即要求只能在手機上運行,為類似QQ這樣不能重新簽名的Android應用編寫自動化測試案例……能夠滿足這個要求的測試技術只有monkey,可是不知道Google是出於什麼考慮,只把monkey設計成一個隨機發送按鍵訊息的程式 – 跟猴子一樣,在手機鍵盤上亂敲亂點;而沒有給monkey加上類似Instrumentation的抓取控制項的支援。
為了滿足測試需求,我們對方案是修改了一點monkey的原始碼,實現在手機真機上,脫離PC機,無需重新簽名測試QQ的用例。修改的原理是:
1、 Android SDK裡有一個工具HierarchyViewer可以顯示Android手機上各應用的UI布局,我們也實現了支援iOS的HierarchyViewer,有興趣的網友可以參閱:http://www.cnblogs.com/vowei/archive/2012/08/13/2614468.html
2、 HierarchyViewer的原理是通過與運行Android手機上的ViewServer建立一個socket串連(這個串連可以通過WIFI,也可以通過USB連接埠),向ViewServer發送命令的形式通訊。
a) 例如,當HierarchyViewer發送 DUMP -1 這個指令時,ViewServer 就會將整個Android系統的UI樹形布局回傳給HierarchyViewer。
b) HierarchyViewer再解析回傳的字串,關於這個過程,我的同事劉斌華寫了一篇非常好的文章:http://www.cnblogs.com/vowei/archive/2012/08/08/2627614.html
3、 因為HierarchyViewer是運行在PC機上的,而ViewServer是運行在手機上的,實際的抓取Android UI控制項樹的過程是由ViewServer來完成的,HierarchyViewer只是一個簡單的用戶端。
4、 而Android系統又是多任務的,可以由好幾個程式同時運行在後台,在手機上抓取UI控制項樹的過程就變得很簡單:
a) 建立到本機ViewServer的socket串連。
b) 跟HierarchyViewer一樣,向ViewServer發送命令並解析回傳的字串,這個字串可以用我們的iQuery解析:https://github.com/vowei/iQuery
c) 預設情況下,ViewServer是出於關閉狀態,需要顯式啟動。
下面是關鍵代碼,開啟monkey主函數的源檔案,Monkey.java,在其main函數裡:
1、 在Monkey調用getSystemInterfaces之後,加上下面這行顯式啟動ViewServer – 其監聽的連接埠號碼是4939。
1: monkey.mWm.startViewServer(4939);
2、 然後在monkey源碼裡,任意的合適的位置,建立一個socket,串連到原生ViewServer上:
1: Socket socket = new Socket();
2: socket.connect(new InetSocketAddress("127.0.0.1", 4939));
3、 與ViewServer通訊:
1: BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
2: BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));
3: out.write("DUMP -1");
4: out.newLine();
5: out.flush();
6: String line = null;
7: int maxCount = 0;
8: while ( (maxCount < 4) && ((line = in.readLine()) != null) ) {
9: ... ...
10: }
因為在手機上啟動ViewServer是一個超級使用者才能做的操作-需要開啟一個網路連接埠,需要使用一台root過的裝置,運行方式是:
1、 找到一個root過的裝置,並安裝一個Terminator應用。
2、在手機上啟動“終端模擬器”程式,並依次執行下列命令:
1: export CLASSPATH=/sdcard/monkey.jar
2: cd /sdcard
3: su
4: #下面這個命令預設會啟動QQ,並列印QQ登入介面上4個TextView控制項上的文本
5: app_process /system/bin com.android.commands.monkey.Monkey
6: #下面這個命令運行指定的Android應用 ,並列印介面上前4個TextView控制項上的文本,第一個參數是包名,第二個參數是要啟動的Activity全名
7: app_process /system/bin com.android.commands.monkey.Monkey com.android.development com.android.development.Development