使用Monkeyrunner進行Android自動化的總結
使用Android自動化的方式,不僅可以用來對Android APP進行自動化測試,同樣可以用來進行一些其他非常有意思的自動化任務.常用的自動化工具有Monkeyrunner, Robotium, Appium等.Monkeyrunner是Android內建的自動化測試載入器,允許使用者對Android裝置的UI介面進行元素提取,執行touch和drag等操作,配合HierarchyViewer等模組可以非常方便地進行自動化操作.
首先,使用者需要安裝好Android開發環境,同時運行Monkeyrunner指令碼需要安裝Jython環境.Jython允許使用Python的文法格式來編寫自動化測試代碼,因此對於Python開發人員而言非常有優勢.Python中的一些個別模組不能直接用於Jython中,這時就需要安裝適用於Jython版本的,具體方法可參考
http://stackoverflow.com/questions/3256135/importing-python-modules-in-jython. 如安裝bottle模組, jython ez_setup.py bottle,然後在使用時匯入該模組即可.
import syssys.path.append('/home/jython2.5.3/Lib/site-packages/bottle-0.12.7-py2.5.egg')from bottle import Bottle, run, request, response, get, post
使用Monkeyrunner進行Android自動化大概可以分為以下幾種類型的操作:裝置及UI介面操作,UI介面元素提取,對比等.
1, 裝置及UI介面操作
其實,涉及到Android裝置的操作,使用開發環境內建的adb已經足夠了,而Monkeyrunner也是將adb操作封裝了以下而已.常見adb操作如下:
adb install xxx.apk安裝apk檔案adb shell am start -an com.xxx.xxx/.MainActivity 啟動APPadb shell am force-stop com.xxx.xxx 停止該APPadb shell input keyevent KEYCODE_HOME 類比Android的HOME按鍵adb -s emulator-5554 shell input text test_to_input 針對特定的一個模擬器進行操作adb shell input tap x y 類比螢幕touch操作adb shell input swipe x1 y1 x2 y2 類比螢幕滑動操作adb devices 查看所有線上的Android裝置.
詳細的adb命令,可以通過adb -h來查詢.而Monkeyrunner中對裝置的操作如下:
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevicedevice = MonkeyRunner.waitForConnection(5,"emulator-5554")device.shell("am start -an com.xxx.xxx/.MainActivity")device.touch(250, 450, 'DOWN_AND_UP')device.drag((1080/2, 1700),(1080/2, 400),0.5,1)device.type("text to type")device.shell("input text" + "text to input")device.press("KEYCODE_HOME")# 另外,也可以通過id來進行touch操作,此時可以引入By模組,可以非常方便通過id尋找對應的元素.from com.android.monkeyrunner.easy import EasyMonkeyDevice, Byeasy_device = EasyMonkeyDevice(device)easy_device.touch(By.id('id/button1'), easy_device.DOWN_AND_UP)
以上方式其實與adb shell的操作是一致的,只是方便使用者在Jython指令檔中調用而已.
2, UI介面元素提取
Monkeyrunner可以通過HierarchyViewer來對UI介面的元素進行解析,解析的結果與DDMS及Android Studio中的Android Device Monitor保持一致.
首先需要先對UI介面進行解析,然後即可通過元素id和其他的屬性來提取該元素,並對其所有屬性進行解析.
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevicefrom com.android.chimpchat.hierarchyviewer import HierarchyViewerdevice = MonkeyRunner.waitForConnection(5,"emulator-5554")hViewer = device.getHierarchyViewer() # 對當前UI視圖進行解析content = hViewer.findViewById('id/content') # 通過id尋找對應元素memberView = content.children[0]text = memberView.namedProperties.get('text:mText').value.encode('utf8')desc = memberView.namedProperties.get('accessibility:getContentDescription()').value.encode('utf8')mleft = memberView.namedProperties.get('layout:mLeft').value.encode('utf8')height = memberView.height
使用HierarchyViewer來解析介面的層級關係,並根據id來尋找特定元素是我們常用的做法.然而,Android APP中,會有很多元素是沒有對應的id的(這一點,可以通過DDMS或者AVD中解析結果看出來),那麼此時,我們如果要精準地找到一個特定元素,就只能通過進一步解析某個元素的children來實現,會比較麻煩,但往往是非常精準的.
需要注意的是,使用HierarchyViewer並通過id來尋找元素偶爾會出錯,提示找不到對應的元素.如果遇到實在難以解析出來的元素,可以考慮使用另一個模組AndroidViewClient進行解析.原理也很類似.甚至有時候,寫法比HierarchyViewer簡潔得多.
vc = ViewClient(device=device, serialno="emulator-5554")content = vc.findViewById('id/content')memberView = content.children[0]text = memberView.getText()x = memberView.getX()y = memberView.getY()height = memberView.getHeight()
AndroidViewClient的項目地址是https://github.com/dtmilano/AndroidViewClient.使用時候有個注意事項,我們先將AndroidViewClient寫入環境變數中,然後要先匯入AndroidViewClient的模組,之後再匯入Monkeyrunner及相應地其他模組,否則會出現找不到AndroidViewClient的錯誤.至於為什麼,大家可以自己嘗試一下就明白了.
import sysreload(sys)sys.setdefaultencoding("utf-8")ANDROID_VIEW_CLIENT_HOME = os.environ['ANDROID_VIEW_CLIENT_HOME']sys.path.append(ANDROID_VIEW_CLIENT_HOME + '/src')from com.dtmilano.android.viewclient import ViewClient, Viewfrom com.android.monkeyrunner import MonkeyRunner, MonkeyDevicefrom com.android.monkeyrunner.easy import EasyMonkeyDevice, Byfrom com.android.chimpchat.hierarchyviewer import HierarchyViewer
不過以上兩種方式,都有可能出現UI元素解析失敗的情況,原因可能是Android相應工具自身的不完善導致的.因為DDMS和AVD也會經常出現無法解析某個UI介面的情況.
具體的應用情境大家自己斟酌吧,總之,能夠完美擷取到所需元素即可.
3, 對比
這是Monkeyrunner非常有特色的一種方式,常用於通過裝置螢幕前後的對比來擷取對執行結果的判斷.
path = "/tmp/images"image = device.takeSnapshot() # image.writeToFile(path+"首頁面".decode('utf-8')+now+'.png','png')#下面就開始對之前的進行對比了#去檔案中找到我們要對比的圖片,與該image1進行對比result = MonkeyRunner.loadImageFromFile('/tmp/images/result.png')#判斷圖片相識度是否是為90%if(image.sameAs(result,0.9)): log.write("圖片對比成功……\n")else: log.write("首頁面圖片對比失敗……\n")
以上,就是通過Monkeyrunner進行Android自動化的一些基本內容.
下邊,將大家容易遇到的一些坑記錄下來,造福廣大人民群眾.
Monkeyrunner容易遇到的一些坑:
1, 中文輸入的問題
Monkeyrunner預設只支援Ascii編碼,所以遇到中文,目前是不能通過adb的input和type進行輸入的.那麼可以採用複製到PC剪貼簿,然後到Android模擬器裡邊進行粘貼的方式.
但需要注意的是,Android模擬器裡邊的剪貼簿的內容是當前PC的焦點從PC案頭環境切換到模擬器介面瞬間時的剪貼簿內容.常見情況是,通過Monkeyrunner指令檔將PC環境中剪貼簿內容向Android模擬器粘貼時,往往會出現粘貼不上我們想要的內容.此時,出於調試目的,我們會檢查在當前PC環境的剪貼簿中,是否是我們需要的內容.然後將滑鼠焦點移入模擬器中,常常發現能夠粘貼上所需的正確內容.,然而,這其實是一個時間差的原因,即PC中的剪貼簿內容正確,然後切換到模擬器介面,剪貼簿內容是從PC環境帶過來的,當然是正確的了.相反,我們在Monkeyrunner指令碼執行後,在剪貼簿操作之前即將當前PC的焦點切換到模擬器中,會發現剪貼簿內容是不正確的.說得有點亂,大家可以好好琢磨,自己實踐一下.
github上有位同學寫了一個小的工具,可以非常方便地執行Android模擬器中的剪貼簿操作,https://github.com/bingwei/inputchineseviaadb.非常好用,大家可以試一試.當然,遇到一些特殊字元,還是需要做一些簡單地轉義等操作的.
2, Monkeyrunner指令碼中各個操作的耗時問題
在Monkeyrunner指令碼執行過程中,使用HierarchyViewer以及AndroidViewClient進行介面元素解析時,會發現findViewById操作的時間消耗很大.尤其是該UI介面上元素非常多的時候,耗時非常明顯.然而,涉及到介面切換時,我們常常會根據當前介面中是否包含某個id的元素來判斷介面是否切換成功.那麼,在大多數情況下,我們沒有必要根據id來判斷當前介面,通過windowName = device.getHierarchyViewer().focusedWindowName()這種方式,已經足夠我們進行絕大多數的UI介面判斷了,並且在效率上絕對不是一個數量級的提升.
3, 涉及到UI介面之間切換的演算法問題
我們常常會遇到,明明就在幾個特定的UI介面之間相互切換,但由於Android自動化環境及工具自身的不穩定性,經常導致螢幕切換延遲,點擊或切換不成功,APP卡住甚至閃退等一些非常苦惱的問題.那麼這就是考驗編碼能力和演算法功底的時候.在這一點上,非常感謝教授同學的協助,贊一個.
我們可以預先定義一個所有常見介面的focusdWindowName及螢幕切換所需的操作行為的結構體,如
SCREEN_SWITCH_ACTION = { 'Activity1': { 'Activity1': None, 'Activity2': ('LEFT_DOWN', 'Activity1'), # 如,從Activity2切換到Activity1需要做LEFT_DOWN的操作. 'Activity3': ('LEFT_DOWN', 'Activity1'), }, 'Activity2': { 'Activity1': ('MID_DOWN', 'Activity2'), 'Activity2': None, 'Activity3': ('MID_DOWN', 'Activity2'), }, 'Activity3': { 'Activity1': ('RIGHT_DOWN', 'Activity3'), 'Activity2': ('RIGHT_DOWN', 'Activity3'), 'Activity3': None, },}
如上,該字典中key是目標螢幕,其value值即代表了從當前螢幕切換到目標螢幕所需的操作行為.其中,LEFT_DOWN等可以是簡單地touch一個button,也可以寫出一個負責的根據介面及元素來決定操作行為的負責操作的集合.有了如上的這種結構體,我們只需要寫一個對應的演算法,在螢幕切換時從該結構體中解析操作並執行即可.諸如螢幕等待,失敗重試之類的容錯機制,都可以隨意添加了.
其實,涉及到這個演算法層面的問題,研究和改進的空間實在是太大了.有興趣的同學可以更深入的討論,歡迎指教.
當然,除了Monkeyrunner, Robotium和Appium等工具也都是使用率非常高的,各有優劣吧.
以上這些,就是本次Monkeyrunner自動化的一些總結,寫的比較簡略,歡迎批評指正.