Android 程式設計師必須掌握的三種自動化測試方法

希爾瓦娜斯女神發表於2016-01-06

在日常的開發中,尤其是app開發,因為不像web端那樣 出錯以後可以熱更新,所以app開發 一般對軟體質量有更高的要求(你可以想一下 一個發出去的版本如果有重大缺陷 需要強制更新新客戶端是多麼蛋疼的事情)。

恩,所以我們app的開發者 一定要學會自己測試自己的程式碼 自己測試自己的app,不要寄希望於測試來幫你找bug,實際上,我工作多年的經驗告訴,絕大多數隱藏極深的bug 都是開發自己發現的。

所以 今天就來教大家幾招,如何測試自己的app,測試自己的模組。

1.Monkey

http://developer.android.com/intl/zh-cn/tools/help/monkey.html 

這個工具是最簡單的,我主要用他來壓力測試,所謂壓力測試就是 亂點。。。模擬各種各樣奇怪的操作 看你的app能不能抗的住。

可以簡單看一下 這個命令的用法。看一下help 介紹的引數說明。

舉例來說:

1 android shell monkey -p 你想測試程式的包名 -v 500

比如 我現在想看看android 系統自帶的日曆應用 在壓力下表現如何。

你看 這個地方模擬器自己就開始瘋狂點選了。當然在實際使用中,我們都是會把次數調到 幾十萬次到幾百萬次,然後下班以後開始跑,第二天來看結果 看看在哪裡出了問題~~。基本上

每日構建完畢以後都會跑一下。Monkey基本上 就是這樣使用的。非常簡單 但是作用也非常有限。不過可以極大幫助你 找出你app的一些隱藏極深的bug。

比如evernote,這個我平常使用的軟體 我自己是沒有碰到過crush的,但是你跑一下monkey,1個多小時 就崩潰了。。。。。所以monkey是提升軟體質量的 好幫手。

 

2.MonkeyRunner

http://developer.android.com/intl/zh-cn/tools/help/monkeyrunner_concepts.html

這個相對於Monkey 來說 就是真正意義上的 自動化測試工具了。只需要編寫指令碼即可完成 我們平時所需要的 大部分  冒煙用例等等。

尤其是在4.x以下的機型裡,由於無法使用uiautomator, MonkeyRunner幾乎就是唯一的自動化測試編寫辦法。

下面我舉個例子,比如我們app裡最常用的登入功能,我們就可以編寫一個指令碼來完成。

 1 # coding=UTF-8
 2 from com.android.monkeyrunner import MonkeyRunner as mr
 3 from com.android.monkeyrunner import MonkeyDevice as md
 4 from com.android.monkeyrunner import MonkeyImage as mi
 5 from com.android.monkeyrunner.easy import EasyMonkeyDevice
 6 from com.android.monkeyrunner.easy import By
 7 
 8 #定義安裝檔案路徑
 9 installPackage = 'C:\\Users\\Administrator\\ViewPageTest\\app\\build\\outputs\\apk\\app-debug.apk'
10 
11 #要測試的程式的包名
12 apkPackageName ='com.example.administrator.viewpagetest'
13 
14 #要啟動的第一個activity的名稱
15 initActivityName=apkPackageName+"/com.example.administrator.viewpagetest.MainActivity"
16 
17 
18 device = mr.waitForConnection()
19 
20 
21 #安裝apk包
22 device.installPackage(installPackage.decode('utf-8'))
23 
24 
25 #啟動應用程式
26 device.startActivity(component=initActivityName)
27 #防止啟動首頁面 需要時間過長
28 mr.sleep(3)
29 
30 easy_device = EasyMonkeyDevice(device)
31 
32 mr.sleep(3)
33 
34 
35 
36 easy_device.type(By.id('id/username_et'),'zhangsan')
37 # 這裡的mr靜止 主要用於演示demo上的gif效果 
38 mr.sleep(2)
39 easy_device.type(By.id('id/password_et'),'123456')
40 mr.sleep(2)
41 easy_device.touch(By.id('id/submit_bt'),md.DOWN_AND_UP)

然後執行他 看看效果:

你看上面的指令碼 完成了 自己安裝apk 輸入使用者名稱和密碼 並且點選登入按鈕的過程。

有人問,你這個模擬登入的過程是模擬出來了,那我怎麼知道 到底登入成功沒有呢?

其實也很簡單。主要有幾個方法。

1.登入成功以後你這個頁面肯定是要跳轉到主介面的對吧,你就用指令碼執行下shell命令 看看主頁面 是否在棧的最上方?(前面我的activity 啟動模式那篇部落格裡講過這個命令的)

2.你可以在log 裡面 列印出登入成功這個訊息 然後用指令碼捕捉到這個log 日誌 就知道是否登入成功了。

3.甚至你還可以捕獲介面上某個控制元件的文字值。

4.比較某個操作結束後的 截圖。儲存為影象以後 和正確操作以後的影象進行對比。

 

這裡我就不繼續往下寫這個指令碼了。有興趣的同學可以自己嘗試 完成日常工作裡的 那些冒煙用例。(意義重大,否則每次發版本 你的那些用例全部要用手點選手機完成一遍 那多麻煩!)

 

此外 我們還可以利用recorder來錄製指令碼,然後再反過來用python執行這個指令碼 來執行我們的測試過程。這個方法 我就不做詳細分析了,很簡單。(但是要注意 這個方法 啟動的 捕捉器 在多數情況下都非常卡頓,所以採用率不高。)

3.UiAutomator

http://developer.android.com/intl/zh-cn/tools/testing-support-library/index.html

這個工具我個人認為是所有android 程式設計師都必須要掌握的,有了這個強大的工具,我們就可以負責任的對自己的程式碼 說 木問題,ok!

此工具 能模擬幾乎所有對android裝置的操作。

而且程式碼也非常簡單 全部都是java程式碼,並且android的api 他還幾乎都能夠使用。簡直酷到沒有朋友!比android studio 自帶的ApplicationTestCase 強到不知道哪裡去了。

在這之前 你需要對gradle指令碼有少許瞭解。具體可參見我的blog http://www.cnblogs.com/punkisnotdead/p/5029125.html

這個工具的原理實際上和http://www.cnblogs.com/punkisnotdead/p/4885572.html 裡面提到的輔助服務是差不多的。都是利用的那個service。

你只要會寫UiAutomator testcase,就意味著你的程式碼 幾乎是永遠不會出錯噠~~

好,下面給出一個基本的例子 來讓你明白 為何這個工具這麼吊。

首先 給出gradle裡的改動:

 1 apply plugin: 'com.android.application'
 2 
 3 android {
 4     compileSdkVersion 23
 5     buildToolsVersion "23.0.2"
 6 
 7     defaultConfig {
 8         //不要遺漏這句話
 9         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
10         applicationId "com.example.administrator.testcaseone"
11         minSdkVersion 18
12         targetSdkVersion 23
13         versionCode 1
14         versionName "1.0"
15     }
16     buildTypes {
17         release {
18             minifyEnabled false
19             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20         }
21     }
22 }
23 
24 dependencies {
25     compile fileTree(dir: 'libs', include: ['*.jar'])
26     testCompile 'junit:junit:4.12'
27     //這個地方要注意了 studio自帶的裡面版本號一般都比較高,如果出錯的話 你要手動把這個版本號調低一點
28     compile 'com.android.support:appcompat-v7:23.0.1'
29     compile 'com.android.support:design:23.0.1'
30     //對這個androidTestCompile不理解的 可以參考我的部落格裡講gradle的那篇
31     androidTestCompile 'com.android.support.test:runner:0.4'
32     androidTestCompile 'com.android.support.test:rules:0.4'
33     androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
34 }

然後變更一個conifg

然後我們就可以在studio裡面直接run我們的testcase啦:

 

好,然後我們來假設一個場景,假設我們現在要做的功能是 有一個介面,介面上有2個輸入框,你在這2個輸入框裡輸入數字以後,點選計算按鈕 

另外一個textview 就會顯示出來 2個數字相加的結果。 那我們的testcase就要來完成 使用者模擬操作的這個過程 並且看看結果是否和我們預想中的相匹配!

(假設我們現在的android程式碼裡這個計算的程式碼是有錯誤的)

1                 textView.setText(Integer.parseInt(et1.getText().toString()) + Integer.parseInt(et2.getText().toString()) + 1 + "");

你看 這裡 我故意加了一個1.

然後寫我們的testcase 注意testcase的位置

 

然後看一下這個testcase的程式碼:

 1 package com.example.administrator.testcaseone;
 2 
 3 import android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner;
 4 import android.support.test.uiautomator.UiAutomatorTestCase;
 5 import android.support.test.uiautomator.UiDevice;
 6 import android.support.test.uiautomator.UiObject;
 7 import android.support.test.uiautomator.UiObjectNotFoundException;
 8 import android.support.test.uiautomator.UiScrollable;
 9 import android.support.test.uiautomator.UiSelector;
10 
11 /**
12  * Created by Administrator on 2016/1/5.
13  */
14 public class FirstUiautomatorTest extends UiAutomatorTestCase {
15 
16     public void testDemo() throws UiObjectNotFoundException {
17 
18         UiDevice.getInstance(getInstrumentation());
19         //19-27 行 其實就是用這個框架提供的功能來直接啟動你的app.
20         //這裡其實主要就是要找到你的app那個textview 然後點選他 具體api自己去慢慢看吧
21         getUiDevice().pressHome();
22         UiScrollable appViews = new UiScrollable(new UiSelector()
23                 .scrollable(true));
24         UiObject myApp = appViews.getChildByText(new UiSelector()
25                 .className("android.widget.TextView"), "TestCaseOne");
26         //要等到新的視窗出來才繼續往下走
27         myApp.clickAndWaitForNewWindow();
28         //29-32行 就很簡單了,無非就是找到介面上的元素。
29         UiObject et1 = new UiObject(new UiSelector().resourceId("com.example.administrator.testcaseone:id/et"));
30         UiObject et2 = new UiObject(new UiSelector().resourceId("com.example.administrator.testcaseone:id/et2"));
31         UiObject bt1 = new UiObject(new UiSelector().resourceId("com.example.administrator.testcaseone:id/bt1"));
32         UiObject tv1 = new UiObject(new UiSelector().resourceId("com.example.administrator.testcaseone:id/tv1"));
33         //這裡的sleep只是為了gif動畫能顯示的更清楚罷了,一般我們自己寫的時候為了用例速度快一點 是不會加sleep的
34         //某些特殊場景除外
35         et1.setText("12");
36         sleep(3000);
37         et2.setText("21");
38         sleep(3000);
39         bt1.click();
40         //12和21相加 明顯應該是33,所以判斷下 我們的程式碼是否正確
41         assertEquals(33, Integer.parseInt(tv1.getText().toString()));
42 
43     }
44 }

然後直接run我們的這個defaluttest,看看模擬器會發生什麼?

 

自動都幫你模擬了使用者的操作,這個testcase就跑完了,然後看下我們的studio:

顯然的也報錯了。並且這個工具能自動捕獲ui錯誤哦~~什麼anr 之類的 都不在話下。有了他,我們就能為自己寫的程式碼負責了,每次發版本之前 跑跑我們寫好的testcase

基本上就能保證我們app的絕大多數流程是ok的~~所以這個工具一定要掌握!至於他其他好多api 我就不過多介紹了,留給你們自己去探索吧!

 

相關文章