Android自動化學習筆記:編寫MonkeyRunner腳本的幾種方式


----------------------------------------------------------------------------------------------------------------------------

小記: 之前用的是公司自己研發的自動化工具,對市面開源的自動化工具知之甚少,所以開始自學開源的自動化工具。

初步學習中,難免會有疏漏和想不到的地方,隨着不斷深入的了解,如有新的體會,會及時修改,不斷進步。

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

二者缺一不可。

可以看下Android的官方文檔中提到這么一句:
To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system.

翻譯過來意思就是說:出於安全考慮,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的機子有導航鍵,現在的機子基本都是直板,所以……)

上:device.press(“KEYCODE_DPAD_UP”,”DOWN_AND_UP”)
下:device.press(“KEYCODE_DPAD_DOWN”,”DOWN_AND_UP”)
左:device.press(“KEYCODE_DPAD_LEFT”,”DOWN_AND_UP”)
右:device.press(“KEYCODE_DPAD_RIGHT”,”DOWN_AND_UP”)

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. python怎么import指定文件夾下的模塊

3. Python中導入子文件夾中的模塊

問題2: wrapEasyMonkey.py腳本報錯,提示:'ImportError: cannot import name ViewNode'

解決方法:將wrapEasyMonkey.py腳本中的from com.android.hierarchyviewerlib.device import ViewNode修改為from com.android.hierarchyviewerlib.models import ViewNode

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM