Espresso浅析和使用
歡迎大家前往騰訊云社區(qū),獲取更多騰訊海量技術(shù)實(shí)踐干貨哦~
Espresso是一個(gè)Google官方提供的Android應(yīng)用UI自動(dòng)化測(cè)試框架。Google希望,當(dāng)Android的開(kāi)發(fā)者利用Espresso寫(xiě)完測(cè)試用例后,能一邊看著測(cè)試用例自動(dòng)執(zhí)行,一邊享受一杯香醇Espresso(濃咖啡)。
Espress有3個(gè)特點(diǎn):
第一個(gè)收錄在Android Testing Supporting Library底下的測(cè)試框架
模擬用戶的操作
自動(dòng)等待,直到UI線程Idle,才會(huì)執(zhí)行測(cè)試代碼
接下來(lái),將從配置、寫(xiě)用例、運(yùn)行一步步介紹Espresso的使用。
0. 項(xiàng)目配置
0.1 修改App的build.gradle
在defaultConfig內(nèi)增加,testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”,用來(lái)運(yùn)行腳本
增加packagingOptions,避免編譯時(shí)候License的沖突
在dependencies中增加相關(guān)的引用(androidTestCompile只有在編譯測(cè)試用例時(shí)候才會(huì)運(yùn)行,普通編譯不會(huì))
下面是build.gradle中涉及到Espresso配置的內(nèi)容
android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
// Espresso 相關(guān)的引用
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'
}
0.2 添加TestRunner
點(diǎn)擊頂欄菜單Run->Edit Configurations,出現(xiàn)如下的窗口后,點(diǎn)擊左上角的”+”,選擇”Android Tests”;
修改新Configuration的名字,選中App Module,輸入Runner,選擇”Show chooer dialog”,點(diǎn)擊”OK”完成
1. 寫(xiě)測(cè)試用例
1.1 三步曲
寫(xiě)UI自動(dòng)化測(cè)試用例,歸結(jié)起來(lái)就是3步:
定位View控件
操作View控件
校驗(yàn)View控件的狀態(tài)
對(duì)應(yīng)Espresso,就是以下3個(gè)方法的調(diào)用:
onView(ViewMatcher)
.perform(ViewAction)
.check(ViewAssertion);
其中,onView是用來(lái)定位View控件的,perform是操作控件的,check是校驗(yàn)View控件的狀態(tài)。他們各自都需要再傳入對(duì)應(yīng)的參數(shù)分別如下:
ViewMatcher,有withId、withText、withClassName等等方法來(lái)定位View控件
ViewAction,有click()、longClick()、pressBack()、swipeLeft()等等方法來(lái)操作View控件
ViewAssertion,有isEnabled()、isLeftOf()、isChecked()等等方法來(lái)校驗(yàn)View控件狀態(tài)
這里有ViewMatcher、ViewAction、ViewAssertion的Cheat Sheet。
1.2 完整測(cè)試用例代碼
這是一個(gè)非常簡(jiǎn)單的測(cè)試用例,通過(guò)R.id.button定位控件,對(duì)它調(diào)用了一下click,最后校驗(yàn)控件是不是enabled狀態(tài)。這里面有一些注解,@Rule修飾的是被測(cè)試的Activity,@Test修飾的方法是測(cè)試用例。
@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()));
}
}
1.3 注意
Getting Started With Espresso 2.0這個(gè)視頻中提到了2個(gè)寫(xiě)測(cè)試用例時(shí)的注意項(xiàng):
避免Activity的層級(jí)跳轉(zhuǎn),測(cè)試用例盡量只在單個(gè)Activity內(nèi)完成。Activity層級(jí)跳轉(zhuǎn)越多,越容易出錯(cuò)
強(qiáng)烈不推薦,直接獲取View的對(duì)象,調(diào)用View的方法來(lái)模擬用戶操作。應(yīng)該統(tǒng)一使用Espresso提供的方法
測(cè)試用例,特別是UI自動(dòng)化測(cè)試用例,應(yīng)該盡量保持邏輯簡(jiǎn)單,覆蓋關(guān)鍵路徑就足矣。因?yàn)閁I變動(dòng)是很頻繁的,越復(fù)雜,維護(hù)成本就越高,投入產(chǎn)出比就會(huì)自然降低了。
2. 運(yùn)行用例
在運(yùn)行菜單中選擇步驟0.2中設(shè)置的TestRunner,點(diǎn)擊執(zhí)行
測(cè)試用例模擬用戶操作自動(dòng)運(yùn)行
測(cè)試用例執(zhí)行完成,在Android Studio的控制臺(tái)上,能看到如下的結(jié)果輸出
其中,看到”Done 3 of 3”標(biāo)識(shí),一共3個(gè)檢查點(diǎn),都檢查通過(guò)了。如果有檢查不通過(guò)的話,右上角的綠色能量條會(huì)變成紅色。
3. 進(jìn)階
3.1 onData的使用
對(duì)于ListView,如果要操作其中的某一個(gè)item,特別是不可見(jiàn)狀態(tài)的item,是不能通過(guò)上述的ViewMatch來(lái)定位的。我們都知道ListView的View是復(fù)用的,不可見(jiàn)狀態(tài)的item并沒(méi)有把內(nèi)容繪制到View上。Espresso針對(duì)AdapterView(ListView的父類(lèi)),提供了onData來(lái)支持。
onData(ObjectMatcher)
.DataOptions
.perform(ViewAction)
.check(ViewAssertion);
onData傳入的是一個(gè)ObjectMather。首先假設(shè)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);
}
}
下面定義一個(gè)withValue()的方法,返回一個(gè)BoundedMatcher。而其中的matchesSafely()方法是用來(lái)判斷match與否的,判斷的邏輯實(shí)現(xiàn)都放在這里。
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));
}
};
}
有了上面的鋪墊,測(cè)試用例寫(xiě)起來(lái)就水到渠成了。在id是R.id.list的AdapterView中找到數(shù)據(jù)項(xiàng)是27,然后執(zhí)行click()操作。
@Test
public void clickItem() {
onData(withValue(27))
.inAdapterView(withId(R.id.list))
.perform(click());
//Do the assertion here.
}
最后需要注意的是,onData()并不適用于RecyclerView,因?yàn)樗皇抢^承自AdapterView。Espresso提供專(zhuān)門(mén)給RecyclerView使用的RecyclerViewActions。
@Test
public void clickItem() {
onView(withId(R.id.recycler_view))
.perform(
RecyclerViewActions.actionOnItemAtPosition(27, click()));
}
3.2 Idling Resource的使用
應(yīng)用開(kāi)發(fā)中很常見(jiàn)的一個(gè)場(chǎng)景是,點(diǎn)擊某個(gè)按鈕,發(fā)起網(wǎng)絡(luò)請(qǐng)求,等請(qǐng)求回來(lái)后解析數(shù)據(jù),更新界面。Espresso針對(duì)這種測(cè)試場(chǎng)景,提供了原生的支持。
假設(shè)被測(cè)Activity初始化后有一個(gè)耗時(shí)的數(shù)據(jù)加載過(guò)程,activity.isSyncFinished()方法判斷數(shù)據(jù)加載是否已經(jīng)完成。代碼如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
//模擬耗時(shí)的數(shù)據(jù)加載
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來(lái)保證數(shù)據(jù)加載完成了才開(kāi)始執(zhí)行測(cè)試用例代碼。首先,需實(shí)現(xiàn)IdlingResource接口:
getName()方法返回的String是作為注冊(cè)回調(diào)的Key,所以要確保唯一性
registerIdleTransitionCallback()的參數(shù)ResourceCallback會(huì)用做isIdleNow()時(shí)候的回調(diào)
isIdleNow()是否已經(jīng)處于空閑狀態(tài),這里調(diào)用activity.isSyncFinished()方法來(lái)判斷數(shù)據(jù)加載是否完成
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需要在恰當(dāng)?shù)臅r(shí)機(jī)注冊(cè)和反注冊(cè)。@Before和@After是依照J(rèn)Unit4的慣例,分別在用例執(zhí)行之前和之后去注冊(cè)和反注冊(cè)。那么,如下測(cè)試用例執(zhí)行的過(guò)程是:
測(cè)試用例啟動(dòng),注冊(cè)MyIdlingResource
啟動(dòng)被測(cè)Activity
Activity初始化,啟動(dòng)數(shù)據(jù)加載過(guò)程
Activity數(shù)據(jù)加載完成,執(zhí)行測(cè)試用例方法testTextViewDisplay()
測(cè)試用例結(jié)束,反注冊(cè)MyIdlingResource
可見(jiàn),IdlingResource能夠保證流轉(zhuǎn)到Idle狀態(tài),才會(huì)執(zhí)行測(cè)試代碼:
@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);
}
3.3. 執(zhí)行原理
本文開(kāi)頭提到Espresso其中一個(gè)特點(diǎn),無(wú)需主動(dòng)寫(xiě)Sleep等待UI事件的執(zhí)行和UI的繪制。原因是,Espresso的用例運(yùn)行過(guò)程是只有當(dāng)UI線程IDLE和UI隊(duì)列沒(méi)有需要執(zhí)行的事件時(shí),Espresso的測(cè)試代碼才會(huì)被執(zhí)行。使用方無(wú)需寫(xiě)Sleep邏輯等待UI繪制完成。以下是Espresso測(cè)試用例執(zhí)行簡(jiǎn)易的流程圖,幫助理解:
寫(xiě)在最后
引用官方介紹的一段話,Espresso的目標(biāo)受眾是開(kāi)發(fā)者。希望更多的團(tuán)隊(duì)能夠?qū)崿F(xiàn)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:https://www.youtube.com/watch?v=TGU0B4qRlHY
Advanced Android Espresso:https://realm.io/news/chiu-ki-chan-advanced-android-espresso-testing/
Android Espresso 測(cè)試框架探究:http://blog.csdn.net/weijianfeng1990912/article/details/51540468
Android自動(dòng)化測(cè)試-AdapterView的測(cè)試:https://segmentfault.com/a/1190000004392396
Android單元測(cè)試研究與實(shí)踐:http://tech.meituan.com/Android_unit_test.html
文章來(lái)自: QQ音樂(lè)技術(shù)團(tuán)隊(duì) 公眾號(hào)
相關(guān)閱讀
網(wǎng)頁(yè)加速特技之 AMP
表格行與列邊框樣式處理的原理分析及實(shí)戰(zhàn)應(yīng)用
「騰訊云游戲開(kāi)發(fā)者技術(shù)沙龍」11月24 日深圳站報(bào)名開(kāi)啟 暢談?dòng)螒蚣铀?/p>
此文已由作者授權(quán)騰訊云技術(shù)社區(qū)發(fā)布,轉(zhuǎn)載請(qǐng)注明原文出處
原文鏈接:https://cloud.tencent.com/community/article/520289?utm_source=bky
海量技術(shù)實(shí)踐經(jīng)驗(yàn),盡在騰訊云社區(qū)!
總結(jié)
以上是生活随笔為你收集整理的Espresso浅析和使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: oracle 物理读突然增加的原因_请教
- 下一篇: cad立面索引符号 规范_一套标准规范施