Android App壓力測試

前言:寫這篇文章的目的,一是因爲不少同學作爲Android開發,很少會自己去做壓力測試,不瞭解相關的技術,不知道壓力測試是什麼、怎麼工作的;二是詢問過身邊的一些測試同學,他們進行壓力測試的時候,很多情況只是執行monkey的隨機操作,也有部分同學不會寫測試腳本,那麼本篇文章就應運而生了!

一、背景

1.爲什麼要進行壓力測試?

我們都知道一款產品上線之前都需要進行的一步操作就是測試驗收,那麼人工手動的測試是帶有一定的偶然性的,因爲沒有人知道哪一步操作會出現問題(例如Crash、ANR等),還有對於一些偶發現象,人爲難以復現的場景,開發人員無法針對性的解決問題,那麼進行壓力測試就是儘可能的模擬各種使用場景,最大程度發現隱藏的問題。

壓力測試的目標:

  • 1.提高產品穩定性
    產品的穩定性是App產品所有指標中非常重要的一項,有機構統計70%的用戶在使用App時會遇到各種不穩定的問題,當出現異常問題時,有的用戶會忍受繼續使用,有的用戶可能就會放棄使用直接卸載App了,這取決於應用的使用場景和發展階段,例如微信、QQ、支付寶等等,人們已經離不開這些和生活息息相關的產品了,哪怕偶爾出現一兩次不穩定的問題,用戶很大程度上也不會卸載,但是如果這發生在一款初創期的App上,用戶可能直接就卸載了,可能給公司帶來致命的打擊。

  • 2.提高產品留存率
    機構統計有5%的用戶在遇到頁面延時響應時間過長的時候,會選擇放棄繼續使用或者卸載App,當用戶對這樣的一款App產生反感情緒時,產品的DAU和留存率就會降低。所以提高產品的穩定性、提高產品的留存率,爲公司帶來更大的收益,壓力測試勢在必行!

2.什麼時候進行壓力測試?

這個沒有明確的要求,但是一般會選擇在首輪功能測試驗收通過後進行,這樣能最大程度避免因爲功能性bug導致的壓力測試結果異常。因爲壓力測試是自動化執行,所以當我們下班的時候,就可以執行測試腳本,第二天早上上班的時候來查看壓力測試結果,測試工作互不耽誤。

二、理論

1.手工測試場景

在這裏插入圖片描述
當我們手工模擬一個搜索操作時,會按照以上的步驟來:1.點擊搜索框(彈起軟鍵盤),2.輸入關鍵詞,3.點擊搜索按鈕,搜索結果就會出現在下面的網頁中。

2.自動測試場景

將我們上述的手工操作,轉換成機器語言,應該是什麼樣呢?
在這裏插入圖片描述
點擊輸入框 -> 輸入關鍵詞(鍵盤事件)-> 點擊搜索 -> 選擇想要查看的結果條目 -> 滾動瀏覽,這就是機器自動化的流程,那麼我們應該做的就是模擬手工操作的事件流。

3.Monkey工具

  • 1.什麼是Monkey?
    Monkey是Android SDK自帶的測試工具,是一個命令行工具,可以運行在模擬器裏或實際設備中。可以運行在模擬器中或者實際設備中,它向系統發送僞隨機的用戶事件流(如按鍵輸入,觸摸屏輸入,手勢輸入等),實現對正在開發的應用程序進行壓力測試。由於測試事件和數據都是隨機的,不能自定義,所以有很大的侷限性。
  • 2.Monkey在哪兒?
    存在於我們的Android手機中,需要藉助ADB來和Monkey進行通信。

4.ADB命令

  • 1.什麼是ADB?
    Android 調試橋 (adb) 是一種功能多樣的命令行工具,可讓您與設備進行通信。adb 命令便於執行各種設備操作(例如安裝和調試應用),並提供對 Unix shell(可用來在設備上運行各種命令)的訪問權限。
  • 2.ADB在哪兒?
    adb 包含在 Android SDK 平臺工具軟件包中。您可以使用 SDK 管理器下載此軟件包,管理器會將此軟件包安裝在 android_sdk/platform-tools/。或者,如果您需要獨立的 Android SDK 平臺工具軟件包,可以點擊此處進行下載

5.什麼是MonkeyScript

MonkeyScript是官方提供的,除了像猴子一樣隨機亂點之外,還可以通過編寫腳本的形式,完成一系列固定的操作。MonkeyScript提供一整套完善的API來進行支持,主要還是基於座標點的操作,包含常用的:點擊、長按、輸入、等待等操作。

6.什麼是MonkeyRunner

monkey和monkeyrunner都是android sdk提供的測試命令,但monkeyrunner和money沒有什麼直接的關係,monkey是在設備直接運行adb shell命令生成隨機事件來進行測試的。相比較而言,monkeyrunner則是通過API發送特定的命令和事件通過工作站來控制設備。
在這裏插入圖片描述

7.MonkeyRunner API

MonkeyRunner工具主要有三個類:MonkeyRunner、MonkeyDevice、MonkeyImage。

  • 1.MonkeyRunner類:提供連接真機和模擬器方法waitForConnection(float timeout,string deviceid),還有顯示提示顯示信息的alert()方法。
  • 2.MonkeyDevice類:提供了安裝和卸載程序包、開啓Activity、發送按鍵和點擊事件、運行測試包等方法。
  • 3.MonkeyImage類:在測試過程中用來保存測試截圖,保存各種格式,並可以比較兩個MonkeyImage對象。

三、實戰

1.App壓力測試實戰

  • 1.在手機開發者選項中,將USB調試勾選。
  • 2.確認手機和電腦已經成功連接。
    在這裏插入圖片描述
    在連接設備列表中能發現自己的設備說明連接成功。
  • 3.安裝測試App
  • 4.發送壓力測試命令(隨機)
adb shell monkey 100

這時手機就會模擬各種隨機操作100次。
在這裏插入圖片描述
執行完後在命令行會看到以下內容:
在這裏插入圖片描述
可以看到我們設置的是執行100次操作,這裏Events injected也收到了100次事件,說明過程中沒有出現異常,否則Events injected數量會少於100,整個操作過程耗時5613ms。

  • 5.獲取App包名
    以上我們執行的是隨機命令,如果我們想針對某一個App進行壓力測試怎麼辦呢?首先我們需要獲取想要測試的App的包名,可以藉助以下一行命令:
adb logcat | grep START

這裏拿計算器應用爲例,執行後,然後點擊手機中的計算器應用,就會發現在最後一行會輸出計算器的相關信息:
在這裏插入圖片描述
其中cmp=com.meizu.flyme.calculator就是計算器的包名了。

  • 6.給指定App進行壓力測試
adb shell monkey -p com.meizu.flyme.calculator 1000

這行代碼會對我們的計算器應用執行1000次的隨機操作。
在這裏插入圖片描述
在這裏插入圖片描述

2.Monkey高級參數的使用

  • 1.throttle參數
    指定事件之間的間隔(毫秒)
adb shell monkey --throttle <milliseconds>
  • 2.seed參數
    指定隨機生成數的seed值
adb shell monkey -s <seed> <event-count>

我們利用monkey進行壓力測試的時候,monkey生成的事件流都是隨機的,如果在執行過程中發生異常的時候,測試同學可能找開發去修改,開發同學要求測試同學復現操作步驟,那麼這個時候就很難復現了。如果我們能夠指定seed值的話,那麼monkey就會執行相同的操作序列,就能很方便的復現之前出現的異常問題。

  • 3.觸摸事件
    設定觸摸事件百分比
adb shell monkey --pct-touch <percent>

同樣以計算器爲例,在命令中增加一個-v參數,能夠看出操作執行過程中的百分比:
在這裏插入圖片描述
Event 0代表的是touch事件,因爲我們指定了–pct-touch 100,所以其他的觸摸事件都是0,touch事件是100,另外下面的結果中出現了多次ACTION_DOWN和ACTION_UP,按下和彈起都是配對出現的,這就是模擬一次點擊過程。

如果我們不指定–pct-touch 100,來看看執行效果:
在這裏插入圖片描述
可以看出事件很隨機的分佈,其中touch事件佔了15%,從下面打出的日誌可以看出,還有像Traceball和rotation這些事件的觸發。

  • 4.動作事件
    設定動作事件百分比
adb shell monkey --pct-motion <percent>

這裏需要注意一點是動作事件和其他事件百分比的和要等於100,如果不等於100的話,則會將剩餘部分隨機操作。
在這裏插入圖片描述
這裏我們指定了touch事件50%,motion事件30%,所以剩下的8種事件類型佔比是隨機分配的。

  • 5.軌跡球事件
    設定軌跡球事件百分比
adb shell monkey --pct-traceball <percent>
  • 6.基本導航事件
    設定基本導航事件百分比,輸入設備的上、下、左、右
adb shell monkey --pct-nav <percent>
  • 7.主要導航事件
    設定主要導航事件百分比,兼容中間鍵、返回鍵、菜單鍵
adb shell monkey --pct-majornav <percent>
  • 8.系統導航事件
    設定系統導航事件百分比,HOME、BACK、撥號和音量鍵
adb shell monkey --pct-syskeys <percent>
  • 9.啓動Activity事件
    設定啓動Activity事件百分比,會在多個app之間進行切換
adb shell monkey --pct-appswitch <percent>
  • 10.不常用事件
    設定不常用事件百分比
adb shell monkey --pct-anyevent <percent>
  • 11.崩潰事件
    忽略崩潰和異常

在monkey執行過程中,如果遇到一次crash,則進程會中斷,不會繼續往下進行,那麼我們如果希望monkey能夠執行完所有的事件的話,就需要用到這個參數。

adb shell monkey --ignore-crashes <event-count>
  • 12.超時事件
    忽略超時事件

和崩潰事件一樣,如果monkey遇到ANR時,也會中斷,所以我們需要忽略超時事件的話,可以用到這個參數。

adb shell monkey --ignore-timeouts <event-count>

3.Crash結果分析

  • 1.安裝一個會發生Crash的app
  • 2.執行monkey進行壓力測試
  • 3.分析Crash的Exception信息

在這裏插入圖片描述
可以看到當monkey觸發了某一個crash事件時,進程停止了,同時會打印出crash的相關信息,這是Event injected事件是533,我們命令中指定的是1000,所以當異常發生時,不會繼續執行剩下的操作。

注意到在log的最後有一行:

System appears to have crashed at event 533 of 1000 using seed 1574782034909

前面我們說過,如果我們想要重複上一次的過程的話,需要指定一個seed值去模擬上一次的操作,這裏可以使用seed 1574782034909,這樣執行過程就會和上次一模一樣,這樣就可以復現我們剛纔崩潰的場景。

如果我們希望出現crash時,monkey仍然執行完1000次操作時,這時就可以用到上面介紹到的–ignore-crashes。
在這裏插入圖片描述
可以看到,我們指定了seed,模擬上一次的操作流,同時也使用了–ignore-crashes,crash發生了,但是仍會執行完,所以Event injected爲1000,但是這個時候想看到seed值會發現沒有了,因爲當crash發生時,仍然要求monkey繼續執行,所以就會隨機生成一個新的seed值。

4.ANR結果分析

  • 1.安裝一個會發生ANR的app
  • 2.執行monkey進行壓力測試
  • 3.分析ANR的Exception信息

日誌非常多,截取部分日誌來看看:
在這裏插入圖片描述
在這裏插入圖片描述
可以看到當執行到第84個操作時,就發生了ANR,發生的原因在日誌中也有具體的描述,如果我們希望復現這個ANR的話,可以依靠此次產生的seed。同理如果希望事件繼續執行完,可以藉助–ignore-timeouts命令。

5.MonkeyScript實戰

在monkey幫我們完成穩定性測試之後,我們如果有一種需求,模擬重複操作事件流100次,而monkey是隨機操作,那麼這時候就要使用MonkeyScript了。

adb shell monkey -f <script-file> <event-count>

在編寫MonkeyScript之前,來先了解一些常用命令:
1.DispatchTrackball命令
軌跡球事件

DispatchTrackball(long downtime,long eventide,int action,float x,float y,
float pressure,float size,int metastate,float xprecision,float yprecision,
int device,int edgeflags)

long downtime指鍵最初被按下的時間
long eventtide指事件發生的時間
int action指具體操作的動作,如按下
float x,float y指x和y的座標
float pressure壓力事件的大小(0~1)
float size指觸摸的記事值(0~1)
int metastate指當前按下mate鍵的標識
float xprecision,float yprecision指x和y座標的精確值
int device事件的來源(0~x)
int edgeflags指超出屏幕了範圍

我們這裏用三個參數就可以了,分別是:
int action(0表示按下,1表示彈起)
如果我們想要模擬點擊事件的話,需要傳輸兩個參數,一個命令傳輸0,表示按下,另一個傳輸1,表示彈起,這樣我們可以實現點擊的過程。

在點擊的過程中,我們需要確定點擊的點,這裏就是指需要確定點擊的範圍,即就是x和y的座標:float xfloat y

2.DispatchPointer命令
點擊事件

DispatchPointer(long downtime,long eventtide,int action,float x,float y,
float pressure,float size,int metastate,float xprecision,float yprecision,
int device,int edgeflags)

參數含義和DispatchTrackball一樣。

3.DispatchString命令
輸入字符串命令

DispatchString(String text)

接收一個要輸入的字符串。

4.LaunchActivity命令
啓動應用

LaunchActivity(package,Activity)

#package指App包名
#Activity指被啓動頁面的名稱

5.UserWait命令
等待事件

UserWait(1000)

等待的時間,單位爲毫秒

6.DispatchPress命令
按下鍵值

DispatchPress(int keycode)

keycode 66 回車鍵
根據自己的需要傳入具體對應的鍵值即可

MonkeyScript實戰部分
在瞭解完上述的幾個命令之後,我們正式開始編寫腳本。這裏我們模擬一個用戶在瀏覽器搜索100次的場景。用戶每次的操作流程如下:
在這裏插入圖片描述
那我們將這幾個步驟轉化爲MonkeyScript支持的語言。

首先MonkeyScript有一些固定的腳本頭,需要寫在腳本的最前面。

type=user
count = 1
speed = 1.0
start data >>

然後纔是我們要執行的步驟腳本,完整的腳本如下:

type=user
count = 1
speed = 1.0
start data >>

LaunchActivity(com.zhangyan.monkeydemo,com.zhangyan.monkeydemo.MainActivity)
UserWait(2000)
DispatchPointer(10,10,0,200,200,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,200,200,1,1,-1,1,1,0,0)
DispatchString(China)
UserWait(1000)
DispatchPress(66)
UserWait(1000)
DispatchPointer(10,10,0,1350,250,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,1350,250,1,1,-1,1,1,0,0)
UserWait(6000)
DispatchPointer(10,10,0,1200,250,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,1200,250,1,1,-1,1,1,0,0)
UserWait(3000)

解釋一下參數:

DispatchPointer(10,10,0,200,200,1,1,-1,1,1,0,0)
DispatchPointer(10,10,1,200,200,1,1,-1,1,1,0,0)

這是一個模擬點擊事件,所以按下和彈起是成對出現的,第三個參數action分別是0和1表示down和up,第四位和第五位參數是點擊的x和y座標點,那麼這個點如何獲取呢?需要藉助Android SDK中的一個uiautomatorviewer,它的路徑在我的/Library/Android/sdk/tools/bin/下,你們可以在你們對應的安裝目錄下找到這個命令。運行起來後如下所示:
在這裏插入圖片描述
我們可以藉助這個獲取我們想要的x和y值,放到參數中就行了。

腳本寫完了保存一下,此時執行adb shell monkey -f monkey.script 2是無效的,爲什麼呢?
因爲monkey是存在我們的手機設備中的,而我的monkey.script腳本存在我的電腦中的,所以手機中的monkey是無法直接獲取到電腦設備的腳本的,所以我們需要將monkey.script放到手機中去,執行以下這段命令:

adb push monkey.script /data/local/tmp/

然後執行這條命令,注意路徑得寫文件的絕對路徑,也就是我們剛纔設置的路徑。

adb shell monkey -f /data/local/tmp/monkey.script 2

在這裏插入圖片描述
可以看到腳本執行起來後,app就會按照我們設定的操作執行,重複的次數就是我們設置的2次,當操作全部執行完成後,終端會有如下信息:
在這裏插入圖片描述
那麼這裏爲什麼Event injected等於30呢?其實這個操作的個數就是我們腳本里的命令數,執行多少次就是它的乘積。

6.MonkeyRunner實戰

MonkeyScript雖然很強大,能夠幫助我們完成豐富的操作,但是它也有很多限制之處,比如我們在自動化過程中想要完成截屏操作,那它就無法完成了,此時就需要用到MonkeyRunner了。

在使用MonkeyRunner之前,來先了解一些常用命令。

MonkeyRunner API 主要通過下面三個包:
MonkeyRunner: 主要提供了MonkeyRunner應用的輔助方法以及用來連接設備或是模擬器的方法,並提供UI支持等。
MonkeyDevice: 代表一個設備或是模擬器,提供安裝、卸載應用的方法,啓動一個 Activity,發送按鍵或是Touch事件等。
MonkeyImage: 代表一個截屏圖像,可以截取不同格式的圖像,比較兩個MonkeyImage圖像,保存圖像等。

1.MonkeyRunner API - alert
警告框

void alert(String message,String title,String okTitle)

下面來寫一段python腳本:

#!/usr/bin/python
#-*- UTF-8 -*-
from com.android.monkeyrunner import MonkeyRunner
MonkeyRunner.alert('Hello World','MonkeyRunner','OK')

執行命令monkeyrunner demo.py
在這裏插入圖片描述
2.MonkeyRunner API - waitForConnection
等待設備連接,有多個device id,需要指明具體哪個設備

waitForConnection(float timeout,String deviceId)//timeout單位爲秒

3.MonkeyRunner API - drag
拖動

drag(tuple start,tuple end,float duration,integer steps)

start:啓動位置
end:終點位置
duration:手勢持續的時間
插值點的步數,默認是10

4.MonkeyRunner API - press
按鍵

press(String keycode,dictionary type)

keycode:按鍵的code
type:按鍵類型:DOWN、UP、DOWN_AND_UP

5.MonkeyDevice API - startActivity
啓動應用

startActivity(package+"/"+activity)

6.MonkeyDevice API - touch
點擊事件

touch(integer x,integer y,integer type)

7.MonkeyDevice API - type
輸入事件

type(String message)

8.MonkeyDevice API - takeSnapshot
截屏事件

MonkeyImage takeSnapshot()

9.MonkeyImage API - sameAs
圖像對比

boolean sameAs(MonkeyImage other,float percent)

10.MonkeyImage API - writeToFile
保存圖像文件

void writeToFile(String path,String format)

MonkeyRunner實戰部分
我們仍然模擬上面的操作,用MonkeyRunner腳本來實現一遍,完整代碼如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice,MonkeyImage
#連接設備
device = MonkeyRunner.waitForConnection(3,"793QADSKAR5G4")
#啓動app
device.startActivity("com.zhangyan.monkeydemo/com.zhangyan.monkeydemo.MainActivity")
MonkeyRunner.sleep(2)
#點擊搜索框
device.touch(200,200,"DOWN_AND_UP")
MonkeyRunner.sleep(1)
#輸入關鍵詞
device.type("China")
MonkeyRunner.sleep(1)
#點擊回車鍵
device.press("KEYCODE_ENTER","DOWN_AND_UP")
MonkeyRunner.sleep(1)
#點擊搜索
device.touch(1350,250,"DOWN_AND_UP")
MonkeyRunner.sleep(3)
#截圖
image = device.takeSnapshot()
image.writeToFile('./takeSnapshot.png','png')
#點擊清除按鈕
device.touch(1200,250,"DOWN_AND_UP")
MonkeyRunner.sleep(3)

我的python腳本放在桌面上,所以進入到桌面目錄,執行以下命令:

monkeyrunner monkeyrunner.py 

等待幾秒設備連接成功,就會看到手機出現和MonkeyScript一樣的操作,不過我們的python腳本中有一個截屏的操作,等待腳本執行完,會看到桌面上有一張我們命名好的圖片,打開看看圖片的內容:
在這裏插入圖片描述
可以看到在我們點擊搜索按鈕後,就執行了截屏命令,保存到指定路徑。

到這裏MonkeyRunner的基本用法就講完了,我們可以看到MonkeyRunner幫助我們完成了整個自動化的過程,如果想要MonkeyRunner執行多次的話,就需要藉助python腳本做這樣的事情,這樣可以完成重複的操作過程。

四、結束語

這篇文章簡單的介紹了Monkey相關的知識,包括基礎的MonkeyScript使用、MonkeyRunner的使用,大家可以藉助這些命令實現自己的一個自動化壓力測試的功能,感謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章