Android自動化測試工具之MonkeyRunner
monkeyrunner工具
前言:
最近開始研究Android自動化測試方法,對其中的一些工具、方法和框架做了一些簡單的整理,其中包括android測試框架、CTS、Monkey、Monkeyrunner、benchmark、其它test tool等等。因接觸時間很短,很多地方有不足之處,希望能和大家多多交流。
一、什麼是monkeyrunner
monkeyrunner工具提供了一個API,使用此API寫出的程式可以在Android程式碼之外控制Android裝置和模擬器。通過monkeyrunner,您可以寫出一個Python程式去安裝一個Android應用程式或測試包,執行它,向它傳送模擬擊鍵,擷取它的使用者介面圖片,並將截圖儲存於工作站上。monkeyrunner工具的主要設計目的是用於測試功能/框架水平上的應用程式和裝置,或用於執行單元測試套件,但您當然也可以將其用於其它目的。
二、monkeyrunner工具同Monkey工具的差別
Monkey:
Monkey工具直接執行在裝置或模擬器的adb shell中,生成使用者或系統的偽隨機事件流。
monkeyrunner:
monkeyrunner工具則是在工作站上通過API定義的特定命令和事件控制裝置或模擬器。
三、monkeyrunner的測試型別
1、多裝置控制:monkeyrunner API可以跨多個裝置或模擬器實施測試套件。您可以在同一時間接上所有的裝置或一次啟動全部模擬器(或統統一起),依據程式依次連線到每一個,然後執行一個或多個測試。您也可以用程式啟動一個配置好的模擬器,執行一個或多個測試,然後關閉模擬器。
2、 功能測試: monkeyrunner可以為一個應用自動貫徹一次功能測試。您提供按鍵或觸控事件的輸入數值,然後觀察輸出結果的截圖。
3、 迴歸測試:monkeyrunner可以執行某個應用,並將其結果截圖與既定已知正確的結果截圖相比較,以此測試應用的穩定性。
4、 可擴充套件的自動化:由於monkeyrunner是一個API工具包,您可以基於Python模組和程式開發一整套系統,以此來控制Android裝置。除了使用monkeyrunner API之外,您還可以使用標準的Python os和subprocess模組來呼叫Android Debug Bridge這樣的Android工具。
四、執行monkeyrunner
您可以直接使用一個程式碼檔案執行monkeyrunner,抑或在互動式對話中輸入monkeyrunner語句。不論使用哪種方式,您都需要呼叫SDK目錄的tools子目錄下的monkeyrunner命令。如果您提供一個檔名作為執行引數,則monkeyrunner將視檔案內容為Python程式,並加以執行;否則,它將提供一個互動對話環境。
monkeyrunner的命令語法為:
monkeyrunner -plugin <plugin_jar> <program_filename> <program_options>
五、例項
以sample中的ApiDemos為例,先將其生成ApiDemos.apk。
前提:已有device連線
1、 將ApiDemos.apk放在$Android_Root\tools下。
2、 在$Android_Root\tools下新建一個monkeyrunnerprogram.py檔案,裡面內容為:
1 # Imports the monkeyrunner modules used by this program 2 3 from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage4 5 # Connects to the current device, returning a MonkeyDevice object 6 7 device = MonkeyRunner.waitForConnection()
8 9 # Installs the Android package. Notice that this method returns a boolean, so you can test10 11 # to see if the installation worked.12 13 device.installPackage('./ApiDemos.apk')
14 15 16 # Runs the component17 18 device.startActivity(component='com.example.android.apis/.ApiDemos')
19 20 21 # Presses the Menu button22 23 device.press('KEYCODE_MENU','DOWN_AND_UP')
24 25 26 # Takes a screenshot27 28 result = device.takeSnapshot()
29 30 31 # Writes the screenshot to a file32 33 result.writeToFile('./shot1.png','png')
注意:SDK上的例子有些錯誤,不可直接複製,否則執行命令時會發生錯誤。具體可與我的上面這段程式碼對照。
3、 開啟命令列轉到Android_Root\tools目錄下執行一下命令:
monkeyrunner monkeyrunnerprogram.py
110307 15:33:19.625:I [main] [com.android.monkeyrunner.MonkeyManager] Monkey Command: wake.
110307 15:33:20.625:I [main] [com.android.monkeyrunner.MonkeyManager] Monkey Command: wake.
110307 15:33:21.625:I [main] [com.android.monkeyrunner.MonkeyManager] Monkey Command: wake.
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] Error starting command: monkey --port 12345
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice]com.android.ddmlib.ShellCommandUnresponsiveException
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:408)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at com.android.ddmlib.Device.executeShellCommand(Device.java:276)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at com.android.monkeyrunner.adb.AdbMonkeyDevice$1.run(AdbMonkeyDevice.java:89)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.util.concurrent.Executors$RunnableAdapter.call(UnknownSource)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.util.concurrent.FutureTask.run(Unknown Source)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.util.concurrent.ThreadPoolExecutor$Worker.run(UnknownSource)
110307 15:33:22.718:S [pool-1-thread-1] [com.android.monkeyrunner.adb.AdbMonkeyDevice] at java.lang.Thread.run(UnknownSource)
110307 15:33:57.437:I [main] [com.android.monkeyrunner.MonkeyManager] Monkey Command: press KEYCODE_MENU.
110307 15:33:59.171:I [main] [com.android.monkeyrunner.MonkeyManager] Monkey Command: quit.
注:裡面exception的提示我們可以忽略,因為我們可以看見 Monkey Command: press KEYCODE_MENU已經執行成功。
4、 可以Android_Root\tools下檢視生成的shot1.png的截圖。
六、例項擴充套件
因為ApiDemos首頁上按下MENU鍵沒有選單出現,為了更加形象化,在例項五的基礎上繼續試驗:
1、 在$Android_Root\tools下新建一個monkeyrunnerprogram1.py檔案,裡面內容為:
1 # Imports the monkeyrunner modules used by this program 2 3 from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage4 5 # Connects to the current device, returning a MonkeyDevice object 6 7 device = MonkeyRunner.waitForConnection()
8 9 # Takes a screenshot10 11 result = device.takeSnapshot()
12 13 # Writes the screenshot to a file14 15 result.writeToFile('./shotbegin.png','png')
16 17 # Presses the Down button18 19 device.press('KEYCODE_DPAD_DOWN','DOWN_AND_UP')
20 21 device.press('KEYCODE_DPAD_DOWN','DOWN_AND_UP')
22 23 device.press('KEYCODE_DPAD_DOWN','DOWN_AND_UP')
24 25 device.press('KEYCODE_DPAD_DOWN','DOWN_AND_UP')
26 27 device.press('KEYCODE_DPAD_DOWN','DOWN_AND_UP')
28 29 # Takes a screenshot30 31 result = device.takeSnapshot()
32 33 # Writes the screenshot to a file34 35 result.writeToFile('./shotend.png','png')
2、 將畫面定位在Apidemos的首頁,並將游標定位在第一項上。
3、 在$Android_Root\tools目錄下執行一下命令:
monkeyrunner monkeyrunnerprogram1.py
4、在執行過程中我們可以看見游標不斷向下移動,並且可以在當前目錄下我們自定義的截圖:
執行前:shotbegin.png
執行後(做了五次下移操作):shotend.png
參考資料: