----------------------------------------------------------------------------------------------------------------------------
小記: 之前用的是公司自己研發的自動化工具,對市面開源的自動化工具知之甚少,所以開始自學開源的自動化工具。
初步學習中,難免會有疏漏和想不到的地方,隨着不斷深入的了解,如有新的體會,會及時修改,不斷進步。
2014-10-17:初版
2014-10-20: 更新通過ID寫腳本的實例
2014-10-23:更新HierarchyViewer提示和獲取ID的方法
2014-10-24:更新第三方插件內容
2014-10-27:更新Q&A--解決了困擾兩天的問題
2016-2-24:刪除一種方式
------------------------------------------------------------------------------------------------------------------------------
提示:
如果HierarchyViewer無法在市場上的android手機上使用,使用的條件是手機必須是工程機:
1.手機已經Root
2.設備支持啟動view service
二者缺一不可。
翻譯過來意思就是說:出於安全考慮,Hierarchy Viewer只能連接Android開發版手機或是模擬器
網上有一些如何把手機root和打開view service的文章,建議不要嘗試,手機容易變磚或者不斷重啟
如果實在按耐不住想拿自己手機試試,可以訪問這里:如何在Root的手機上開啟ViewServer,使得HierachyViewer能夠連接
================================================================================
研究monkeyrunner已經有5天了,前面更新了幾篇筆記,先總結一下感覺:
- MonkeyRunner可以通過獲取坐標點去點擊目標對象,在引入EasyMonkeyDevice后可以根據ID進行點擊對象
- MonkeyRunner也有第三方的插件,增加了一些實用方法,不過沒有花時間嘗試
- Eclipse上寫Python代碼時,很多對象沒有成員函數提示(即使導入過jar包也無用,不過如果寫過同樣的代碼,放在同包的其他文件里,會有部分成員函數的提示信息) :如MonkeyRunner.waitForConnection()獲得device對象后,后面devie.不能自動提示可用成員函數
- 性能不是很好,在使用hierarchyviewer獲取ID時,明顯感覺需要很長時間
- 穩定性也不是很好,在使用hierarchyviewer獲取ID時,有時候成功,有時候會失敗
- 沒有任何junit的繼承,嘗試使用unit框架來使用MonkeyRunner,不過遇到importError。
- 官網API更新不及時,資料很少,網上找來找去,內容基本都相差無幾
- 不過相較robotium支持多設備連接,這個確實是一大優點
今天內容是整理一下最新學到的monkeyrunner腳本的幾種方式。
1. 通過光標定位,采用上下左右導航鍵控制(記憶中是Android剛出來的時候,寢室室友買了個HTC的機子有導航鍵,現在的機子基本都是直板,所以……)
2. 通過指定坐標的方式(這種方式是最直接的,也是最笨的,因為不同設備的分辨率不同,腳本不可復用,不過可以直接計算出新的坐標,以后再說……)
詳細測試腳本可參照:Android自動化學習筆記:MonkeyRunner官方介紹和簡單實例 :實例是用HierarchyViewer得到坐標,然后touch坐標或者press key event寫的monkeyrunner腳本。
觸摸:touch (integer x, integer y, integer type) Sends a touch event specified by type to the screen location specified by x and y.
點擊:press (string name, dictionary type) Sends the key event specified by type to the key specified by keycode.
3. 通過錄制回放的方式(這種方式能夠迅速生成一個腳本,不過不是python的腳本)
詳細測試腳本可參照:Android自動化學習筆記:MonkeyRunner錄制和回放
4. 通過獲取控件文本的方式(用於apk里控件文本不相同的時候使用,所以如果文本顯示相同的話,不可使用,這需要采用第三方插件viewClient)
詳細配置和使用方法可參考: https://github.com/dtmilano/AndroidViewClient 自己去看咯.
已經獨立成單獨一個工具,可以忽略。
5. 通過獲取控件ID的方式(這種方式比較合適,寫一次腳本適用於不同分辨率的手機,但是也需要APK的ID不重復)
下面對calculator.apk來寫monkeyrunner腳本:
得到ID: 打開HierarchyViewer->點擊Load view Hierarchy
A. 第一種寫法:獲取HierarchyViewer對象
這里我們也有兩個方法:
①可以引入 from com.android.chimpchat.hierarchyviewer import HierarchyViewer
②也可以直接通過hierarchyviewer = device.getHierarchyViewer()來創建
monkeydevice里的源碼:
示例:
獲取控件viewNode->得到中心點坐標->選擇
''' Created on Oct 20, 2014 @author: deldong ''' import sys from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage logFile = open("C:\\monkeyrunner_log.txt","a+") #連接設備 device = MonkeyRunner.waitForConnection() if not device: print("Please connect a device to start!") logFile.write("Please connect a device to start!\n") else: print("Device Connected successfully!") logFile.write("Device Connected successfully!\n") package = 'com.android.calculator2' activity = 'com.android.calculator2.Calculator' runComponent = package + '/' + activity #啟動計算器 print("Start calculator") logFile.write("Start calculator") device.startActivity(component=runComponent) #等待時間 print("Wait 15s") logFile.write("Wait 15s") MonkeyRunner.sleep(15) #獲取控件對象 print("Get widget object") logFile.write("Get widget object") hierarchyviewer = device.getHierarchyViewer() #得到8,9,*,=的viewnode對象 #舉例:viewNode對象的值:com.android.calculator2.CalculatorDisplay@b3ffd170 viewDigit8 = hierarchyviewer.findViewById("id/digit8") viewDigit9 = hierarchyviewer.findViewById("id/digit9") viewMul = hierarchyviewer.findViewById("id/mul") viewEqual = hierarchyviewer.findViewById("id/equal") #獲取控件的中心坐標 #舉例:pointView的中心點坐標的值:Point {240, 116} print("Get location of view") logFile.write("Get location of view") pointViewDigit8 = hierarchyviewer.getAbsoluteCenterOfView(viewDigit8) pointViewDigit9 = hierarchyviewer.getAbsoluteCenterOfView(viewDigit9) pointViewMul = hierarchyviewer.getAbsoluteCenterOfView(viewMul) pointViewEqual = hierarchyviewer.getAbsoluteCenterOfView(viewEqual) #計算8*9=72的結果 print("touch 8*9=") logFile.write("touch 8*9=") MonkeyRunner.sleep(5) device.touch(pointViewDigit8,'DOWN_AND_UP') device.touch(pointViewMul,'DOWN_AND_UP') device.touch(pointViewDigit9,'DOWN_AND_UP') device.touch(pointViewEqual,'DOWN_AND_UP') logFile.close()
B. 第二種寫法:通過EasyMonkeyDevice類和By類來調用控件ID
''' Created on Oct 23, 2014 @author: deldong ''' import sys import math reload(sys) sys.setdefaultencoding("utf-8") from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice from com.android.monkeyrunner.easy import EasyMonkeyDevice from com.android.monkeyrunner.easy import By #connect device print('connect device!') device = MonkeyRunner.waitForConnection() #start activity print('start activity') package = 'com.android.calculator2' activity = 'com.android.calculator2.Calculator' runComponent = package + '/' + activity device.startActivity(component=runComponent) MonkeyRunner.sleep(15) #init easymonkeydevice object ,this is init method print('init easymonkeydevice') easy_device = EasyMonkeyDevice(device) print('Tap 8') easy_device.touch(By.id('id/digit8'),MonkeyDevice.DOWN_AND_UP) MonkeyRunner.sleep(1.0) print('Tap *') easy_device.touch(By.id('id/mul'),MonkeyDevice.DOWN_AND_UP) MonkeyRunner.sleep(1.0) print('Tap 9') easy_device.touch(By.id('id/digit9'),MonkeyDevice.DOWN_AND_UP) MonkeyRunner.sleep(1.0) print('Tap =') easy_device.touch(By.id('id/equal'),MonkeyDevice.DOWN_AND_UP) MonkeyRunner.sleep(1.0) pic = device.takeSnapshot() pic.writeToFile('./result.png','png') print('test finished!')
C. 第三種寫法:通過wrapeasymonkey來寫
先上網址(打不開的用代理) :
https://sourceforge.net/projects/wrapeasymonkey/
http://blog.whoistester.com
中文博客:http://lihao.cf/category/my-work/wrapeasydevice/
在官網上復制的內容:
本文章內容在僅windows 7上經過試驗,使用該庫主要目的,
1. 將monkeyDevice 與 easyMonkeyDevice統一封裝到庫
2. 進行自動化操作時, 增加對異常處理,防止異常退出 (例如 當某textview未顯示出來時, 捕捉對該textview的操作異常,防止測試腳本異常退出. 如果手動在腳本里加入sleep語句, 但sleep的時間難以指定)
3. 增加了一些比較便捷的函數, 降低了使用 monkeyDevice 和 easyMonkeyDevice 的復雜度。
另需要說明的是: 該wrapEasyMonkey 庫是加入了androidviewclient庫。 androidviewclient庫是Diego Torres Milano 開發的。
如何使用呢。 請先到sourceforge進行下載wrapEasyMonkey源碼。(可能需要掛代理)
Q&A:
問題1:執行時,出現importError : no module named xxx的異常:
解決方法:
這個問題比較麻煩,因為直接用python + 文件方式,就可以正常執行。
但是用monkeyrunner + 文件的方式,就會有importError產生。
搗鼓了幾天,一直沒搞清楚到底是哪里的問題。不過今天很開心的是,嘗試出一個臨時解決這個問題的方式。
寫了一個簡單的腳本說明:
package1包里有個testPy文件:
import sys print(sys.path) from package2 import helperPy helperPy.printHelper() if __name__ == '__main__': pass
package2包里有個helperPy文件,里面有個printHelper方法
''' Created on Oct 27, 2014 @author: deldong ''' def printHelper(): print("this is print helper") if __name__ == '__main__': pass
執行:
可以看出,環境變量里,只有package1的文件路徑,沒有package2的。
那怎么辦呢,解決方式就是,咱們自己把package2給加進去。
import sys sys.path.append("C:\\Nokia\\adt-bundle-windows-x86-20140702\\eclipse\\workspace\\項目名")
解決問題靈感來自:
1. Monkeyrunner ImportError: No module named util
問題2: wrapEasyMonkey.py腳本報錯,提示:'ImportError: cannot import name ViewNode'
解決方法:將wrapEasyMonkey.py腳本中的from com.android.hierarchyviewerlib.device import ViewNode修改為from com.android.hierarchyviewerlib.models import ViewNode