zz:使用Monkeyrunner进行Android自动化的总结
使用Monkeyrunner進(jìn)行Android自動(dòng)化的總結(jié)
使用Android自動(dòng)化的方式,不僅可以用來對(duì)Android APP進(jìn)行自動(dòng)化測試,同樣可以用來進(jìn)行一些其他非常有意思的自動(dòng)化任務(wù).常用的自動(dòng)化工具有Monkeyrunner, Robotium, Appium等.Monkeyrunner是Android自帶的自動(dòng)化測試工具,允許用戶對(duì)Android設(shè)備的UI界面進(jìn)行元素提取,執(zhí)行touch和drag等操作,配合HierarchyViewer等模塊可以非常方便地進(jìn)行自動(dòng)化操作.
首先,用戶需要安裝好Android開發(fā)環(huán)境,同時(shí)運(yùn)行Monkeyrunner腳本需要安裝Jython環(huán)境.Jython允許使用Python的語法格式來編寫自動(dòng)化測試代碼,因此對(duì)于Python開發(fā)者而言非常有優(yōu)勢.Python中的一些個(gè)別模塊不能直接用于Jython中,這時(shí)就需要安裝適用于Jython版本的,具體方法可參考
?
http://stackoverflow.com/questions/3256135/importing-python-modules-in-jython. 如安裝bottle模塊, jython ez_setup.py bottle,然后在使用時(shí)導(dǎo)入該模塊即可.
?
?
?| 1 2 3 | import sys sys.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 |
?
1, 設(shè)備及UI界面操作
其實(shí),涉及到Android設(shè)備的操作,使用開發(fā)環(huán)境自帶的adb已經(jīng)足夠了,而Monkeyrunner也是將adb操作封裝了以下而已.常見adb操作如下:
?
?| 1 2 3 4 5 6 7 8 | adb install xxx.apk 安裝apk文件 adb shell am start -an com.xxx.xxx/.MainActivity 啟動(dòng)APP adb shell am force-stop com.xxx.xxx 停止該APP adb shell input keyevent KEYCODE_HOME 模擬Android的HOME按鍵 adb -s emulator-5554 shell input text test_to_input 針對(duì)特定的一個(gè)模擬器進(jìn)行操作 adb shell input tap x y 模擬屏幕touch操作 adb shell input swipe x1 y1 x2 y2 模擬屏幕滑動(dòng)操作 adb devices 查看所有在線的Android設(shè)備. |
?
詳細(xì)的adb命令,可以通過adb -h來查詢.而Monkeyrunner中對(duì)設(shè)備的操作如下:
?
?| 1 2 3 4 5 6 7 8 9 10 11 12 | from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice device = 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來進(jìn)行touch操作,此時(shí)可以引入By模塊,可以非常方便通過id尋找對(duì)應(yīng)的元素. from com.android.monkeyrunner.easy import EasyMonkeyDevice, By easy_device = EasyMonkeyDevice(device) easy_device.touch(By.id('id/button1'), easy_device.DOWN_AND_UP) |
?
2, UI界面元素提取
Monkeyrunner可以通過HierarchyViewer來對(duì)UI界面的元素進(jìn)行解析,解析的結(jié)果與DDMS及Android Studio中的Android Device Monitor保持一致.
首先需要先對(duì)UI界面進(jìn)行解析,然后即可通過元素id和其他的屬性來提取該元素,并對(duì)其所有屬性進(jìn)行解析.
?
?| 1 2 3 4 5 6 7 8 9 10 | from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice from com.android.chimpchat.hierarchyviewer import HierarchyViewer device = MonkeyRunner.waitForConnection(5,"emulator-5554") hViewer = device.getHierarchyViewer() # 對(duì)當(dāng)前UI視圖進(jìn)行解析 content = hViewer.findViewById('id/content')? # 通過id查找對(duì)應(yīng)元素 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來解析界面的層級(jí)關(guān)系,并根據(jù)id來查找特定元素是我們常用的做法.然而,Android APP中,會(huì)有很多元素是沒有對(duì)應(yīng)的id的(這一點(diǎn),可以通過DDMS或者AVD中解析結(jié)果看出來),那么此時(shí),我們?nèi)绻珳?zhǔn)地找到一個(gè)特定元素,就只能通過進(jìn)一步解析某個(gè)元素的children來實(shí)現(xiàn),會(huì)比較麻煩,但往往是非常精準(zhǔn)的.
需要注意的是,使用HierarchyViewer并通過id來查找元素偶爾會(huì)出錯(cuò),提示找不到對(duì)應(yīng)的元素.如果遇到實(shí)在難以解析出來的元素,可以考慮使用另一個(gè)模塊AndroidViewClient進(jìn)行解析.原理也很類似.甚至有時(shí)候,寫法比HierarchyViewer簡潔得多.?
?| 1 2 3 4 5 6 7 | 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的項(xiàng)目地址是https://github.com/dtmilano/AndroidViewClient.使用時(shí)候有個(gè)注意事項(xiàng),我們先將AndroidViewClient寫入環(huán)境變量中,然后要先導(dǎo)入AndroidViewClient的模塊,之后再導(dǎo)入Monkeyrunner及相應(yīng)地其他模塊,否則會(huì)出現(xiàn)找不到AndroidViewClient的錯(cuò)誤.至于為什么,大家可以自己嘗試一下就明白了.
?
?| 1 2 3 4 5 6 7 8 9 10 | import sys reload(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, View from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice from com.android.monkeyrunner.easy import EasyMonkeyDevice, By from com.android.chimpchat.hierarchyviewer import HierarchyViewer |
?
不過以上兩種方式,都有可能出現(xiàn)UI元素解析失敗的情況,原因可能是Android相應(yīng)工具自身的不完善導(dǎo)致的.因?yàn)镈DMS和AVD也會(huì)經(jīng)常出現(xiàn)無法解析某個(gè)UI界面的情況.具體的應(yīng)用場景大家自己斟酌吧,總之,能夠完美獲取到所需元素即可.
3, 截圖對(duì)比
這是Monkeyrunner非常有特色的一種方式,常用于通過設(shè)備屏幕前后的對(duì)比來獲取對(duì)執(zhí)行結(jié)果的判斷.
?
?| 1 2 3 4 5 6 7 8 9 10 11 | path = "/tmp/images" image = device.takeSnapshot() # 截圖 image.writeToFile(path+"主頁面".decode('utf-8')+now+'.png','png') #下面就開始對(duì)之前的截圖進(jìn)行對(duì)比了 #去文件中找到我們要對(duì)比的圖片,與該截圖image1進(jìn)行對(duì)比 result = MonkeyRunner.loadImageFromFile('/tmp/images/result.png') #判斷圖片相識(shí)度是否是為90% if(image.sameAs(result,0.9)): ????log.write("圖片對(duì)比成功……\n") else: ????log.write("主頁面圖片對(duì)比失敗……\n") |
?
?
下邊,將大家容易遇到的一些坑記錄下來,造福廣大人民群眾.
Monkeyrunner容易遇到的一些坑:
1, 中文輸入的問題
Monkeyrunner默認(rèn)只支持Ascii編碼,所以遇到中文,目前是不能通過adb的input和type進(jìn)行輸入的.那么可以采用復(fù)制到PC剪貼板,然后到Android模擬器里邊進(jìn)行粘貼的方式.
但需要注意的是,Android模擬器里邊的剪貼板的內(nèi)容是當(dāng)前PC的焦點(diǎn)從PC桌面環(huán)境切換到模擬器界面瞬間時(shí)的剪貼板內(nèi)容.常見情況是,通過Monkeyrunner腳本文件將PC環(huán)境中剪貼板內(nèi)容向Android模擬器粘貼時(shí),往往會(huì)出現(xiàn)粘貼不上我們想要的內(nèi)容.此時(shí),出于調(diào)試目的,我們會(huì)檢查在當(dāng)前PC環(huán)境的剪貼板中,是否是我們需要的內(nèi)容.然后將鼠標(biāo)焦點(diǎn)移入模擬器中,常常發(fā)現(xiàn)能夠粘貼上所需的正確內(nèi)容.,然而,這其實(shí)是一個(gè)時(shí)間差的原因,即PC中的剪貼板內(nèi)容正確,然后切換到模擬器界面,剪貼板內(nèi)容是從PC環(huán)境帶過來的,當(dāng)然是正確的了.相反,我們?cè)贛onkeyrunner腳本執(zhí)行后,在剪貼板操作之前即將當(dāng)前PC的焦點(diǎn)切換到模擬器中,會(huì)發(fā)現(xiàn)剪貼板內(nèi)容是不正確的.說得有點(diǎn)亂,大家可以好好琢磨,自己實(shí)踐一下.
github上有位同學(xué)寫了一個(gè)小的工具,可以非常方便地執(zhí)行Android模擬器中的剪貼板操作,https://github.com/bingwei/inputchineseviaadb.非常好用,大家可以試一試.當(dāng)然,遇到一些特殊字符,還是需要做一些簡單地轉(zhuǎn)義等操作的.
2, Monkeyrunner腳本中各個(gè)操作的耗時(shí)問題
在Monkeyrunner腳本執(zhí)行過程中,使用HierarchyViewer以及AndroidViewClient進(jìn)行界面元素解析時(shí),會(huì)發(fā)現(xiàn)findViewById操作的時(shí)間消耗很大.尤其是該UI界面上元素非常多的時(shí)候,耗時(shí)非常明顯.然而,涉及到界面切換時(shí),我們常常會(huì)根據(jù)當(dāng)前界面中是否包含某個(gè)id的元素來判斷界面是否切換成功.那么,在大多數(shù)情況下,我們沒有必要根據(jù)id來判斷當(dāng)前界面,通過windowName = device.getHierarchyViewer().focusedWindowName()這種方式,已經(jīng)足夠我們進(jìn)行絕大多數(shù)的UI界面判斷了,并且在效率上絕對(duì)不是一個(gè)數(shù)量級(jí)的提升.
3, 涉及到UI界面之間切換的算法問題
我們常常會(huì)遇到,明明就在幾個(gè)特定的UI界面之間相互切換,但由于Android自動(dòng)化環(huán)境及工具自身的不穩(wěn)定性,經(jīng)常導(dǎo)致屏幕切換延遲,點(diǎn)擊或切換不成功,APP卡住甚至閃退等一些非??鄲赖膯栴}.那么這就是考驗(yàn)編碼能力和算法功底的時(shí)候.在這一點(diǎn)上,非常感謝教授同學(xué)的幫助,贊一個(gè).
我們可以預(yù)先定義一個(gè)所有常見界面的focusdWindowName及屏幕切換所需的操作行為的結(jié)構(gòu)體,如
?
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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, ????}, } |
?
其實(shí),涉及到這個(gè)算法層面的問題,研究和改進(jìn)的空間實(shí)在是太大了.有興趣的同學(xué)可以更深入的討論,歡迎指教.
當(dāng)然,除了Monkeyrunner, Robotium和Appium等工具也都是使用率非常高的,各有優(yōu)劣吧.
以上這些,就是本次Monkeyrunner自動(dòng)化的一些總結(jié),寫的比較簡略,歡迎批評(píng)指正.
?
?
?
總結(jié)
以上是生活随笔為你收集整理的zz:使用Monkeyrunner进行Android自动化的总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【win10】电脑蓝牙开关找不到了的解决
- 下一篇: dto转化 vo_微服务篇-DTO、VO