### 1、Monkeyrunner簡介
monkeyrunner即android SDK中自帶的工具之一,此工具提供API可按制android設備或模擬器。
monkeyrunner提供了一個API,使用此API寫出的程序可以在Android代碼之外控制Android設備和模擬器。通過monkeyrunner,您可以寫出一個Python程序去安裝一個Android應用程序或測試包,運行它,向它發送模擬擊鍵,截取它的用戶界面圖片,并將截圖存儲于工作站上。
monkeyrunner工具的主要目的是用于測試功能/框架水平上的應用程序和設備,或用于運行單元測試套件,但您當然也可以將其用于其它目的。
### 2、Monkeyrunner工具特性
多設備控制:monkeyrunner API可以跨多個設備或模擬器實施測試套件。您可以在同一時間接上所有的設備或一次啟動全部模擬器(或統統一起),依據程序依次連接到每一個,然后運行一個或多個測試。您也可以用程序啟動一個配置好的模擬器,運行一個或多個測試,然后關閉模擬器。
功能測試:monkeyrunner可以為一個應用自動化功能測試。為您提供按鍵或觸摸事件的輸入數值,然后觀察輸出結果的截屏。
回歸測試:monkeyrunner可以運行某個應用,并將其結果截屏與既定已知正確的結果截屏相比較,以此測試應用的穩定性。
可擴展的自動化:由于monkeyrunner是一個API工具包,您可以基于Python模塊和程序開發一整套系統,以此來控制Android設備。除了使用monkeyrunner??? API之外,您還可以使用標準的Python??? os和subprocess模塊來調用如adb這樣的Android工具。
### 3、Monkeyrunner工具同Monkey工具的差別
Monkey:
Monkey工具直接運行在設備或模擬器的adb shell中,生成用戶或系統的偽隨機事件流。
Monkeyrunner:
Monkeyrunner工具是在工作站上通過API定義的特定命令和事件控制設備或模擬器。
Monkeyrunner的優勢
1)Monkeyrunner工具在工作站上通過API定義的特定命令和事件控制設備或模擬器(可控)
2)精確控制事件之間的事件
3)可以進行:點觸屏、拖拽、長按、鍵盤事件
4)可以智能截圖對比和判斷
5)回溯出詳細具體的BUG路徑
Monkeyrunner優缺點
1) 能完全模擬人工所有操作
2) 有詳細的API文檔參考
3) 可以寫出智能圖像對比腳本
4) 支持java和Python兩種語言腳本
5) 腳本移植性差
6)僅支持Android平臺
### **4、Monkeyrunner環境搭建**
Monkeyrunner的環境搭建,需要安裝以下工具:jdk、android sdk、python編譯器 及pythonIDE(如果是用Java編寫腳本還需搭建Java的開發環境即JavaIDE)
### 5、運行Monkeyrunner
Monkeyrunner API
主要包括三個模塊
1、MonkeyRunner:這個類提供了用于連接monkeyrunner和設備或模擬器的方法,它還提供了用于創建用戶界面顯示提供了方法。
2、MonkeyDevice:代表一個設備或模擬器。這個類為安裝和卸載包、開啟Activity、發送按鍵和觸摸事件、運行測試包等提供了方法。
3、MonkeyImage:這個類提供了捕捉屏幕的方法。這個類為截圖、將位圖轉換成各種格式、對比兩個MonkeyImage對象、將image保存到文件等提供了方法。
#引用導入API
Monkeyrunner API
主要包括三個模塊
1、MonkeyRunner:這個類提供了用于連接monkeyrunner和設備或模擬器的方法,它還提供了用于創建用戶界面顯示提供了方法。
2、MonkeyDevice:代表一個設備或模擬器。這個類為安裝和卸載包、開啟Activity、發送按鍵和觸摸事件、運行測試包等提供了方法。
3、MonkeyImage:這個類提供了捕捉屏幕的方法。這個類為截圖、將位圖轉換成各種格式、對比兩個MonkeyImage對象、將image保存到文件等提供了方法
>[danger]# 實例演示
引用導入API
from ?com.android.monkeyrunner import??<module>
運行monkeyrunner
命令語法為:
monkeyrunner -plugin <plugin_jar> <program_filename> <program_options>
方式一:在CMD命令窗口直接運行monkeyrunner
方式二:使用Python編寫測試代碼文件,在CMD中執行monkeyrunner Findyou.py運行
不論使用哪種方式,您都需要調用SDK目錄的tools子目錄下的monkeyrunner命令。
注意:在運行monkeyrunner之前必須先運行相應的模擬器或連接真機,否則monkeyrunner無法連接到設備
運行模擬器有兩種方法:1、通過eclipse中執行模擬器 2、在CMD中通過命令調用模擬器
這里介紹通過命令,在CMD中執行模擬器的方法
emulator?-avd?test
上面命令中test是指模擬器的名稱。
問題:CMD運行提示monkeyrunner不是內部或外部命令,也不是可運行的程序或批處理文件。
解決:電腦環境變量未配置,將monkeyrunner所在目錄配在環境變量里。
變量名:Path
變量值:D:\\android\\android-sdk-windows\\tools;D:\\android\\android-sdk-windows\\platform-tools
### 5、實例
**實例一:卸載舊的APP,安裝新的APP**
**準備**
a.連接安卓真機設備
b.運行CMD,檢測是否連接成功
CMD>adb devices

問題:CMD運行提示adb不是內部或外部命令,也不是可運行的程序或批處理文件。
解決:電腦環境變量未配置,將adb所在目錄配在環境變量里。
>[danger] # monkeyRunner常用API介紹
```
# python引入monkeyRunner模塊
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
# 連接設備, 獲得一個MonkeyDevice對象
device = MonkeyRunner.waitForConnection()
# 安裝apk包. 返回值是boolean,可以判斷是否安裝成功
device.installPackage('myproject/bin/MyApplication.apk')
# sets a variable with the package's internal name
package = 'com.example.android.myapplication'
# sets a variable with the name of an Activity in the package
activity = 'com.example.android.myapplication.MainActivity'
# sets the name of the component to start
runComponent = package + '/' + activity
# 啟動應用程序
device.startActivity(component=runComponent)
# 按下手機的菜單鍵
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
# 截圖
result = device.takeSnapshot()
# 保存截圖
result.writeToFile('myproject/shot1.png','png')
```
>[danger] # monkeyRunner常用API介紹2
```
#需要引入的模塊
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
#等待設備連接,30秒超時,后面是設備名稱,該名稱可以通過執行命令行`adb devices`獲得
device = mr.waitForConnection(30,'123123135002735')
#安裝apk包
device.installPackage('d:/有道詞典V4.0.3.apk'.decode('utf-8'))
#卸載應用程序
device.removePackage('com.youdao.dict')
#啟動應用程序
device.startActivity(component='com.youdao.dict/.activity.DictSplashActivity')
#等待程序加載,5秒
mr.sleep(5)
#拖動操作,四個參數,前兩個是初始點、結束點坐標,0.5是持續時間,1是步數
device.drag((550,500),(100,500), 0.5, 1)
#觸摸操作,三個參數,X坐標、Y坐標,觸摸類型
device.touch(80, 1050, "DOWN_AND_UP")
#截圖并保存,注意如果名字中有中文,需要進行utf-8編碼,否則亂碼
now = time.strftime("%Y-%m-%d-%H-%M-%S")
mainPageImage = device.takeSnapshot()
mainPageImage.writeToFile("d:/"+"主頁面截圖".decode("utf-8")+now+".png", "png")
#點擊后退鍵,鍵盤碼詳情可以去查sdk幫助文檔,路徑:android-sdk-windows/docs/reference/android/view/KeyEvent.html
device.press("KEYCODE_BACK", "DOWN_AND_UP")
#將日志輸出到外部文件,在python中使用中文,需要在文件開頭將編碼設置為utf-8,否則亂碼
log = open('d:/monkenyLog.txt', 'w')
log.write("等待手機連接...、\n")
log.close()
#截圖比較,sameAs()第二個參數表示相似度,0表示完全不相似,1表示完全相同
imageTrue = mr.loadImageFromFile('d:/shot/true.png')
if(imageTrue.sameAs(mainPageImage, 0.75)):
log.write('截圖比較成功\n')
else:
log.write('截圖比較失敗\n')
```
**方式一:**
1.打開CMD,運行monkeyrunner
2.進入monkeyrunner的shell命令交互模式后,逐條輸入以下命令
1from?com.android.monkeyrunner?import?MonkeyRunner,?MonkeyDevice,?MonkeyImage
2?device?=?MonkeyRunner.waitForConnection()
3?device.removePackage('cn.richinfo.thinkdrive')
4?device.installPackage('E:\\\\JAVA\\\\monkeyrunner\\\\Test1\\\\ThinkDrive\_new.apk')
注:每條命令的作用,請見方法二中的注解
實操如圖:

c.檢查手機app是否已更新
**\*方式二:**
**a.編寫Python測試代碼**
# File: Test1.py
# Vision: V1.0
# Author: Findyou
# 引入本程序所用到的模塊
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
# 連接手機設備
device = MonkeyRunner.waitForConnection()
# 截圖
result = device.takeSnapshot()
# 將截圖保存到文件
result.writeToFile('E:\\JAVA\\monkeyrunner\\Test1\\Test1_001.png','png')
# 卸載APP
device.removePackage('cn.richinfo.thinkdrive')
print ('Uninstall Success!')
# 暫停5秒
MonkeyRunner.sleep(5)
# 截圖
result = device.takeSnapshot()
result.writeToFile('E:\\JAVA\\monkeyrunner\\Test1\\Test1_002.png','png')
# 安裝新的APP
device.installPackage('E:\\JAVA\\monkeyrunner\\Test1\\ThinkDrive_new.apk')
print ('Install Success!')
# 截圖
result = device.takeSnapshot()
result.writeToFile('E:\\JAVA\\monkeyrunner\\Test1\\Test1_003.png','png')
注:拷貝運行時請去掉中文注釋;或者在開頭加入?#coding=utf-8
**b.執行Test1.py腳本**
Monkeyrunner?E:\\JAVA\\monkeyrunner\\Test1\\Test1.py
實操如圖:

c.檢查手機app是否已更新
### 6、學習筆記
#引入程序所用的模塊
from?com.android.monkeyrunner?import?MonkeyRunner,?MonkeyDevice,?MonkeyImage
#引入程序所用的模塊,使用別名
from?com.android.monkeyrunner?import?MonkeyRunner?as?mr
from?com.android.monkeyrunner?import?MonkeyDevice?as?md
from?com.android.monkeyrunner?import?MonkeyImage?as?mi
如果給導入的模塊起了別名,就必須使用別名,否則會出現錯誤。
比如連接設備或模擬器,起了以上別名后,命令應該如下:
device=mr.waitForConnection()
#連接到設備或模擬器
#參數1:超時時間,單位秒,浮點數。默認是無限期地等待。
#參數2:串deviceid,指定的設備名稱。默認為當前設備(手機優先,比如手機通過USB線連接到PC、其次為模擬器)。
#默認連接:
device = MonkeyRunner.waitForConnection()
#參數連接:
device = MonkeyRunner.waitForConnection(1.0,'4df74b8XXXXXXX')
#向設備或模擬器安裝APK
#以下兩種方式都是對的
device.installPackage('E:/JAVA/monkeyrunner/Test1/ThinkDrive\_new.apk')
device.installPackage('E:\\\\JAVA\\\\monkeyrunner\\\\Test1\\\\ThinkDrive\_new.apk')
#參數可以為絕對路徑,也可為相對路徑
#卸載設備或模擬器中的APK
#參數為APK包名
device.removePackage('cn.richinfo.thinkdrive')
#啟動任意的Activity
#device.startActivity(component="包名/啟動Activity")
#以下兩種都OK
device.startActivity(component="cn.richinfo.thinkdrive/cn.richinfo.thinkdrive.ui.activities.NavigateActivity")
device.startActivity(component="cn.richinfo.thinkdrive/.ui.activities.NavigateActivity")
#手機截圖
#獲取設備的屏蔽緩沖區,產生了整個顯示器的屏蔽捕獲。(截圖)
result=device.takeSnapshot()
#返回一個MonkeyImage對象(點陣圖包裝),我們可以用以下命令將圖保存到文件
result.writeToFile('E:\\\\JAVA\\\\monkeyrunner\\\\Test1\\\\Test1\_001.png','png')
#暫停
#暫停目前正在運行的程序指定的秒數
#MonkeyRunner.sleep(秒數,浮點數)
MonkeyRunner.sleep(5)
#字符串發送到鍵盤
#device.type('字符串')
device.type('Findyou')
#喚醒設備屏幕
#鎖屏后,屏幕關閉,可以用下命令喚醒
device.wake()
#重起手機
device.reboot()
#模擬滑動
device.drag(X,Y,D,S)
X?開始坐標
Y?結束坐標
D?拖動持續時間(以秒為單位),默認1.0秒
S?插值點時要采取的步驟。默認值是10
device.drag((100,1053),(520,1053),0.1,10)
#在指定位置發送觸摸事件
device.touch(x,y,觸摸事件類型)
x,y的單位為像素
觸摸事件類型,請見下文中Findyou對device.press描述
device.touch(520,520,'DOWN\_AND\_UP')
#發送指定類型指定鍵碼的事件
#device.press(參數1:鍵碼,參數2:觸摸事件類型)
#參數1:見android.view.KeyEvent
#參數2,如有TouchPressType()返回的類型-觸摸事件類型,有三種。
#1、DOWN 發送一個DOWN事件。指定DOWN事件類型發送到設備,對應的按一個鍵或觸摸屏幕上。
#2、UP 發送一個UP事件。指定UP事件類型發送到設備,對應釋放一個鍵或從屏幕上抬起。
#3、DOWN_AND_UP 發送一個DOWN事件,然后一個UP事件。對應于輸入鍵或點擊屏幕。
以上三種事件做為press()參數或touch()參數
#按下HOME鍵
device.press('KEYCODE_HOME',MonkeyDevice.DOWN_AND_UP)
#按下BACK鍵
device.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
#按下下導航鍵
device.press('KEYCODE_DPAD_DOWN',MonkeyDevice.DOWN_AND_UP)
#按下上導航鍵
device.press('KEYCODE_DPAD_UP',MonkeyDevice.DOWN_AND_UP)
#按下OK鍵
device.press('KEYCODE_DPAD_CENTER',MonkeyDevice.DOWN_AND_UP)
KeyCode:?
home鍵 KEYCODE\_HOME?
back鍵 KEYCODE\_BACK?
send鍵 KEYCODE\_CALL?
end鍵 KEYCODE\_ENDCALL?
上導航鍵 KEYCODE\_DPAD\_UP?
下導航鍵 KEYCODE\_DPAD\_DOWN?
左導航 KEYCODE\_DPAD\_LEFT?
右導航鍵 KEYCODE\_DPAD\_RIGHT ?
ok鍵 KEYCODE\_DPAD\_CENTER?
上音量鍵 KEYCODE\_VOLUME\_UP ?
下音量鍵 KEYCODE\_VOLUME\_DOWN?
power鍵 KEYCODE\_POWER?
camera鍵 KEYCODE\_CAMERA?
menu鍵 KEYCODE\_MENU