Espresso是一個Google官方提供的Android應用UI自動化測試框架。Google但願,當Android的開發者利用Espresso寫完測試用例後,能一邊看着測試用例自動執行,一邊享受一杯香醇Espresso(濃咖啡)。
Espress有3個特色:html
接下來,將從配置、寫用例、運行一步步介紹Espresso的使用。java
build.gradle
中涉及到Espresso配置的內容android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
// Espresso 相關的引用
compile 'com.android.support:support-annotations:22.1.1'
androidTestCompile 'com.android.support:support-annotations:22.1.1'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.1'){
exclude group: 'javax.inject'
}
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.1'
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.1'
androidTestCompile 'com.android.support.test:runner:0.2'
}
複製代碼
點擊頂欄菜單Run->Edit Configurations,出現以下的窗口後,點擊左上角的」+」,選擇」Android Tests」;android
修改新Configuration的名字,選中App Module,輸入Runner,選擇」Show chooer dialog」,點擊」OK」完成segmentfault
寫UI自動化測試用例,歸結起來就是3步:bash
定位View控件
操做View控件
校驗View控件的狀態
對應Espresso,就是如下3個方法的調用:網絡
onView(ViewMatcher)
.perform(ViewAction)
.check(ViewAssertion);
複製代碼
其中,onView是用來定位View控件的,perform是操做控件的,check是校驗View控件的狀態。他們各自都須要再傳入對應的參數分別以下:app
ViewMatcher,有withId、withText、withClassName等等方法來定位View控件
ViewAction,有click()、longClick()、pressBack()、swipeLeft()等等方法來操做View控件
ViewAssertion,有isEnabled()、isLeftOf()、isChecked()等等方法來校驗View控件狀態
這裏有ViewMatcher
、ViewAction
、ViewAssertion
的Cheat Sheet。框架
這是一個很是簡單的測試用例,經過R.id.button定位控件,對它調用了一下click,最後校驗控件是否是enabled狀態。這裏面有一些註解,@Rule
修飾的是被測試的Activity
,@Test
修飾的方法是測試用例。ide
@RunWith(AndroidJUnit4.class)public class MainActivityTest { @Rule
public ActivityTestRule mActivityRule = new ActivityTestRule(MainActivity.class); @Test
public void testTextViewDisplay() {
onView(withId(R.id.button))
.perform(click())
.check(matches(isEnabled()));
}
}
複製代碼
Getting Started With Espresso 2.0這個視頻中提到了2個寫測試用例時的注意項:oop
避免Activity
的層級跳轉,測試用例儘可能只在單個Activity
內完成。Activity
層級跳轉越多,越容易出錯
強烈不推薦,直接獲取View
的對象,調用View
的方法來模擬用戶操做。應該統一使用Espresso提供的方法
測試用例,特別是UI自動化測試用例,應該儘可能保持邏輯簡單,覆蓋關鍵路徑就足矣。由於UI變更是很頻繁的,越複雜,維護成本就越高,投入產出比就會天然下降了。
TestRunner
,點擊執行其中,看到」Done 3 of 3」標識,一共3個檢查點,都檢查經過了。若是有檢查不經過的話,右上角的綠色能量條會變成紅色。
對於ListView
,若是要操做其中的某一個item,特別是不可見狀態的item,是不能經過上述的ViewMatch
來定位的。咱們都知道ListView
的View
是複用的,不可見狀態的item並無把內容繪製到View
上。Espresso針對AdapterView
(ListView
的父類),提供了onData
來支持。
onData(ObjectMatcher)
.DataOptions
.perform(ViewAction)
.check(ViewAssertion);
複製代碼
onData
傳入的是一個ObjectMather
。首先假設ListView的Adapter中的Item的定義以下:
public static class Item {
private final int value;
public Item(int value) {
this.value = value;
}
public String toString() {
return String.valueOf(value);
}
}
複製代碼
下面定義一個withValue()
的方法,返回一個BoundedMatcher
。而其中的matchesSafely()
方法是用來判斷match與否的,判斷的邏輯實現都放在這裏。
public static Matcher<Object> withValue(final int value) {
return new BoundedMatcher<Object,
MainActivity.Item>(MainActivity.Item.class) {
@Override public void describeTo(Description description) {
description.appendText("has value " + value);
}
@Override public boolean matchesSafely(
MainActivity.Item item) {
return item.toString().equals(String.valueOf(value));
}
};
}
複製代碼
有了上面的鋪墊,測試用例寫起來就水到渠成了。在id是R.id.list
的AdapterView
中找到數據項是27
,而後執行click()
操做。
@Test
public void clickItem() {
onData(withValue(27))
.inAdapterView(withId(R.id.list))
.perform(click());
//Do the assertion here.
}
複製代碼
最後須要注意的是,onData()
並不適用於RecyclerView
,由於它不是繼承自AdapterView
。Espresso提供專門給RecyclerView
使用的RecyclerViewActions
。
@Test
public void clickItem() {
onView(withId(R.id.recycler_view))
.perform(
RecyclerViewActions.actionOnItemAtPosition(27, click()));
}
複製代碼
應用開發中很常見的一個場景是,點擊某個按鈕,發起網絡請求,等請求回來後解析數據,更新界面。Espresso針對這種測試場景,提供了原生的支持。
假設被測Activity初始化後有一個耗時的數據加載過程,activity.isSyncFinished()方法判斷數據加載是否已經完成。代碼以下:
@Override
protected void onCreate(Bundle savedInstanceState) {
//模擬耗時的數據加載
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
mIsSyncFinished = true;
}
}, 5000);
}
private volatile boolean mIsSyncFinished = false;
public boolean isSyncFinished() {
return mIsSyncFinished;
}
複製代碼
這種狀況,Espresso提供了IdlingResource
來保證數據加載完成了纔開始執行測試用例代碼。首先,需實現IdlingResource
接口:
private static class MyIdlingResource implements IdlingResource {
private ResourceCallback mCallback = null;
private MainActivity mActivity;
MyIdlingResource(MainActivity activity) {
mActivity = activity;
}
@Override
public String getName() {
return "MyIdlingResource";
}
@Override
public void registerIdleTransitionCallback(ResourceCallback callback) {
mCallback = callback;
}
@Override
public boolean isIdleNow() {
boolean isIdle = mActivity != null && mActivity.isSyncFinished();
if (isIdle && mCallback != null) {
mCallback.onTransitionToIdle();
}
return isIdle;
}
}
複製代碼
MyIdlingResource
須要在恰當的時機註冊和反註冊。@Before
和@After
是依照JUnit4的慣例,分別在用例執行以前和以後去註冊和反註冊。那麼,以下測試用例執行的過程是:
@Test
public void testTextViewDisplay() {
onView(withText("Show SnackBar")).check(ViewAssertions.matches(isDisplayed()));
}
@Before
public void registerIntentServiceIdlingResource() {
Activity activity = mActivityRule.getActivity();
idlingResource = new MyIdlingResource((MainActivity) activity);
Espresso.registerIdlingResources(idlingResource);
}
@After
public void unregisterIntentServiceIdlingResource() {
Espresso.unregisterIdlingResources(idlingResource);
}
複製代碼
本文開頭提到Espresso其中一個特色,無需主動寫Sleep等待UI事件的執行和UI的繪製。緣由是,Espresso的用例運行過程是隻有當UI線程IDLE和UI隊列沒有須要執行的事件時,Espresso的測試代碼纔會被執行。使用方無需寫Sleep邏輯等待UI繪製完成。如下是Espresso測試用例執行簡易的流程圖,幫助理解:
引用官方介紹的一段話,Espresso的目標受衆是開發者。但願更多的團隊可以實現Google的期許最大化利用Espresso,把Bug扼殺在搖籃中。
Target Audience
Espresso is targeted at developers, who believe that automated testing is an integral part of the development lifecycle. While it can be used for black-box testing, Espresso’s full power is unlocked by those who are familiar with the codebase under test.
Getting Started With Espresso 2.0:www.youtube.com/watch?v=TGU…
Advanced Android Espresso:realm.io/news/chiu-k…
Android Espresso 測試框架探究:blog.csdn.net/weijianfeng…
Android自動化測試-AdapterView的測試:segmentfault.com/a/119000000…
Android單元測試研究與實踐:tech.meituan.com/Android_uni…
文章來自: QQ音樂技術團隊 公衆號
此文已由做者受權騰訊雲技術社區發佈,轉載請註明原文出處
原文連接:cloud.tencent.com/community/a…
海量技術實踐經驗,盡在騰訊雲社區!