1.介紹
Android團隊在4.1版本(API 16)中推出了一款全新的UI自動化測試工具UiAutomator,用來幫助開發人員更有效率的完成App的Debug工作,同時對于測試人員也是一大福音,為什么這么說呢?
測試:“我發現了一個bug,你寫的App打開A頁面,再打開B頁面有時會出現閃屏問題。”
開發:“嗯?還有這樣的問題,復現給我看看。(內心獨白:我寫的App怎么會有bug,一定是你用的姿勢不對)”
測試:一段忙碌的操作之后...“咦,怎么不出現了?”
開發:“那你先回去吧,復現再告訴我。”
幾天過去了...
測試:滿心歡喜狀,“上次那個問題我復現了,操作給你看....我去,怎么又不出現了!”
開發:“是不是設備有問題,你換個設備再試試呢?”
測試:“寶寶心里苦,但是寶寶不說!”
有了UiAutomator之后:
測試:“我發現了一個bug,你寫的App打開A頁面,再打開B頁面有時會出現閃屏問題。”
開發:“這個簡單,我用UiAutomator寫個測試用例,分分鐘解決。”
測試:“厲害了Word哥!”
全劇終!
UiAutomator提供了以下兩種工具來支持UI自動化測試:
uiautomatorviewer:用來分析UI控件的圖形界面工具,位于SDK目錄下的tools文件夾中。
uiautomator:一個java庫,提供執行自動化測試的各種API。
2.環境搭建
本文使用了Android Studio作為IDE,Eclipse,Please go home!
首先在app根目錄的build.gradle文件中加入依賴:
// AS默認配置,如果如果沒有記得加上
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
注意:uiautomator庫支持的最低版本為API 18,所以本篇文章開發環境的minSdkVersion為18。
配置testInstrumentationRunner為AndroidJunitRunner:
defaultConfig {
...
// 這個AS會為我們默認配置,如果沒有記得加上
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
看下完整的build.gradle文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.yl.uiautomatordemo"
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}
在dependencies中用到了compile、testCompile、androidTestCompile三種依賴方式,讓我們來看看他們有什么區別:
compile:參與編譯,并且會打包到debug/release apk中。
testCompile:只參與單元測試編譯,不會打包到debug/release apk包中,不需要設備支持。
androidTestCompile:只參與UI測試編譯,不會打包到debug/release apk包中,需要設備支持。
除此之外還有Provided、APK、Debug compile和Release compile:
Provided:只參與編譯,不會打包到debug/release apk中。
APK:不參與編譯,只會打包到debug/release apk中。
Debug compile:只參與debug編譯,只會打包到debug apk中。
Release compile:只參與release編譯,只會打包到release apk中。
3.測試流程
1.安裝被測試App到手機中。
2.打開UI分析工具uiautomatorviewer.bat,分析當前UI的界面元素,確保App的各個控件可以被測試工具獲取到。
3.根據App使用流程編寫測試用例。
4.運行測試用例進行測試,定位bug,解決bug。
4.實踐
以《可折疊的Toolbar—CollapsingToolbarLayout》中的Demo為例,假設反復滑動布局會導致應用crash,針對這種情況,我們來寫一個測試用例:
分析UI的界面元素
啟動被測試App,打開uiautomatorviewer.bat工具,點擊左上角的Device Screenshot按鈕捕獲屏幕快照,如下圖所示,左側顯示屏幕快照,右側顯示布局結構與控件屬性,控件屬性在編寫測試用例時會用到。
編寫測試用例
選擇File—New—New Project新建項目,和創建普通項目的流程相同,只不過不需要創建Activity,創建完成后,項目結構如下圖所示:
可以看到,在app—src目錄下,AS為我們自動創建了一個androidTest文件夾,用來編寫UI測試用例,同級還有一個test文件夾,用來編寫單元測試用例。
項目創建成功后,參考上文引入依賴,構建完成后,開始寫測試用例吧!等等,先別急,在此之前先普及一下uiautomator的常用API:
-
UiDevice:
設備對象,通過UiDevice的getInstance(instrumentation)方法獲取,可以通過UiDevice實例來檢測設備的各種屬性,比如獲取屏幕的方向、尺寸等,還可以通過UiDevice實例來執行設備級別的操作,比如點擊Home鍵、返回鍵等:
// 點擊Home鍵 uiDevice.pressHome(); // 點擊返回鍵 uiDevice.pressBack(); ...
-
UiSelector
用于獲取某些符合條件的UI控件對象,可以通過資源id、描述等熟悉獲取:
// 通過資源id獲取 new UiSelector().resourceId("com.yang.designsupportdemo:id/CollapsingToolbarLayout"); // 通過描述文件獲取 new UiSelector().description("Navigate up") // 通過className獲取 new UiSelector().className("android.support.v7.widget.RecyclerView") ...
-
UiObject
代表一個UI控件,通過uiDevice的findObject(UiSelector)方法獲取,獲取到UiObject實例后,就可以對UI控件進行相關的操作,比如點擊、長按等:
// 點擊應用返回按鈕 UiObject back = uiDevice.findObject(new UiSelector().description("Navigate up")); back.click();
-
UiCollection
代表UI控件集合,相當于ViewGroup,比如界面中有多個CheckBox時,可以通過類名獲取到當前界面下的所有CheckBox,然后通過控件id獲取指定的CheckBox對象:
// 獲取指定的CheckBox對象 UiCollection uiCollection = new UiCollection(new UiSelector().className("類名")); UiObject checkBox = uiCollection.getChild(new UiSelector().resourceId(""));
-
UiScrollable
代表可滾動的控件,比如打開設置的關于手機選項:
// 滑動列表到最后,點擊About phone選項 UiScrollable settings = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView")); UiObject about = settings.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "About phone"); about.click();
看下滾動效果:
OK,常用API到這里就說的差不多了,開始寫測試用例吧!
Talk is cheap, Show me the code.
public class UiTest extends TestCase {
public void testA() throws UiObjectNotFoundException {
// 獲取設備對象
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
UiDevice uiDevice = UiDevice.getInstance(instrumentation);
// 獲取上下文
Context context = instrumentation.getContext();
// 啟動測試App
Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.yang.designsupportdemo");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
// 打開CollapsingToolbarLayout
String resourceId = "com.yang.designsupportdemo:id/CollapsingToolbarLayout";
UiObject collapsingToolbarLayout = uiDevice.findObject(new UiSelector().resourceId(resourceId));
collapsingToolbarLayout.click();
for (int i = 0; i < 5; i++) {
// 向上移動
uiDevice.swipe(uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight(),
uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight() / 2, 10);
// 向下移動
uiDevice.swipe(uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight() / 2,
uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight(), 10);
}
// 點擊應用返回按鈕
UiObject back = uiDevice.findObject(new UiSelector().description("Navigate up"));
back.click();
// 點擊設備返回按鈕
uiDevice.pressBack();
}
}
代碼中寫了很全的注釋,簡單說下,首先獲取設備對象和上下文,這個后面要用到,然后啟動測試App,打開需要測試的界面,上下滑動5次后退出App,由于上文中對API已經有了一定了解,看起代碼來還是很輕松的。
注意:測試方法需要以test開頭,如果存在多個測試方法,以test后的字母順序執行。
代碼寫完了,接下來就要開始測試了,右擊測試類選擇Run按鈕,或者點擊測試類中的執行按鈕進行測試,上面的按鈕代表執行所有測試方法,下面的按鈕代表只執行當前測試方法:
測試執行后,可以看到控制臺上打印了一些信息:
可以看到,首先通過adb shell命令在設備中安裝了UiAutomatorDemo和com.yl.uiautomatordemo.test兩個apk,然后啟動測試,此時被測App已經開始執行測試流程,執行完成后,顯示測試結果,看下App的執行效果:
OK,到這里,UiAutomator的基本用法就講完了。
5.寫在最后
源碼已托管到GitHub上,歡迎Fork,覺得還不錯就Start一下吧!
歡迎同學們吐槽評論,如果你覺得本篇博客對你有用,那么就留個言或者點下喜歡吧(^-^)