我們常常聽到這樣的問題:“為什么軟件的開發(fā)者們不適合測試他們自己開發(fā)的軟件?”。事實(shí)上,要回答這個(gè)問題需要明白開發(fā)者去進(jìn)行測試的目的。本篇文章不會(huì)深入到自動(dòng)化測試的具體細(xì)節(jié),是對如何減少重復(fù)測試進(jìn)行簡單實(shí)踐,讓業(yè)務(wù)開發(fā)人員能夠簡單快速上手才是最終目的。

開發(fā)人員測試自己所開發(fā)軟件的行為就像學(xué)生在完成考試后對自己的成績進(jìn)行評估,所以可能會(huì)出現(xiàn)下面的問題:
- 開發(fā)人員對其所寫代碼有主觀認(rèn)同感
- 開發(fā)人員對軟件過于樂觀的心態(tài)
- 開發(fā)人員對需求易產(chǎn)生偏差與混淆
- 開發(fā)人員擅長修復(fù)但不擅長拆解
- 開發(fā)人員缺乏對軟件后續(xù)開發(fā)的展望
- 開發(fā)人員缺乏測試經(jīng)驗(yàn)和方法
開發(fā)者測試的目的
就如前面所說,軟件開發(fā)者測試自己開發(fā)的程序好像并沒多大意義,測試工程師具有很多優(yōu)勢條件,那作為開發(fā)者進(jìn)行自動(dòng)化測試的目的是什么?
其實(shí)從下面的圖就能解釋一切,程序員這個(gè)職業(yè)存在的意義不就是最大化利用機(jī)器,通過自動(dòng)化來完成工作嗎?

作為軟件開發(fā)者需求很明顯,當(dāng)需要對自己開發(fā)的功能進(jìn)行驗(yàn)證時(shí),總是需要反復(fù)調(diào)試后才能提測。這不可避免的需要我們重復(fù)UI操作去覆蓋測試路徑,通過查看界面內(nèi)容和日志輸出驗(yàn)證問題。而UI自動(dòng)化測試恰恰可以滿足這一點(diǎn),減少我們重復(fù)操作ui驗(yàn)證的步驟。
Android自動(dòng)化測試介紹
關(guān)于Android自動(dòng)化測試,可以去官網(wǎng)看一下介紹Getting Started with Testing。

本篇文章不會(huì)對深入到自動(dòng)化測試的細(xì)節(jié)進(jìn)行描述,只是作為開發(fā)人員對如何減少重復(fù)工作量進(jìn)行簡單的實(shí)踐,所以這里直接推薦騰訊U測社區(qū)的一篇文章:5個(gè)最佳的Android測試框架,有興趣的童鞋可以了解一下目前主流的自動(dòng)化測試框架。

解放你的雙手
作為一個(gè)業(yè)務(wù)開發(fā)人員,解放雙手進(jìn)行功能驗(yàn)證性測試才是最根本的需求,所以下面介紹一下使用Espresso進(jìn)行UI自動(dòng)化測試的流程。
為什么選擇Espresso測試框架?
很簡單,Espresso是Google針對Android平臺(tái)開源的一款最新的Android自動(dòng)化測試框架。不用考慮跨平臺(tái)、兼容性等各種問題,最貼合需求才是最好的。
UI自動(dòng)化測試依據(jù)
UI自動(dòng)化測試的基本思路:把自己當(dāng)成用戶,只關(guān)注我能看到的東西。
我們把自己作為使用程序的最終用戶,要讓機(jī)器模擬我的測試過程,那么就需要針對那些我能看到的東西,也就是UI組件進(jìn)行驗(yàn)證。
比如說,作為用戶并不關(guān)心某個(gè)網(wǎng)絡(luò)請求返回值的具體數(shù)據(jù)是否正確,我關(guān)心的是能在UI上看到希望看到的結(jié)果。
基于此,做各個(gè)測試用例的一個(gè)通用的思路就是:找到某個(gè)元素,做一些操作,檢查結(jié)果。這里包含了三個(gè)流程:
- 找元素:找到UI上測試所針對的元素;
- 做操作:給這個(gè)元素做一些操作;
- 檢查結(jié)果:這個(gè)元素做出了我期望的行為。
再直觀一點(diǎn),我們測試向一個(gè)EditText輸入一段文字,那么整個(gè)過程就可以描述為:
- 找元素:找到EditText組件;
- 做操作:向EditText輸入字符串;
- 檢查結(jié)果:EditText顯示了我輸入的字符串,驗(yàn)證內(nèi)容是否符合。
以上三個(gè)小步驟實(shí)際上也是我們作為用戶在使用一個(gè)APP的時(shí)候所遵循的流程。而我們的測試也是基本遵循這樣一個(gè)流程的。下面是官方文檔中給出的一個(gè)簡單測試用例的代碼:
@Test
public void greeterSaysHello() {
onView(withId(R.id.name_field))
.perform(typeText("Steve"));
onView(withId(R.id.greet_button))
.perform(click());
onView(withText("Hello Steve!"))
.check(matches(isDisplayed()));
}
代碼邏輯也是典型的三步:
首先通過withId方法找到了id為name_field的EditText組件,并且調(diào)用typeText方法對其進(jìn)行設(shè)置text內(nèi)容為"Steve";
再通過withId方法找到id為greet_button的Button組件,掉頭click方法模擬點(diǎn)擊該按鈕;
最后通過withText方法查找text內(nèi)容等于"Hello Steve!"的TextView組件,調(diào)用check方法判斷該組件是否匹配(matches方法)是否可見狀態(tài)(isDisplayed)。

UI自動(dòng)化具體實(shí)例
這里建議參照官方文檔給出的步驟進(jìn)行實(shí)踐,示例給出自己在實(shí)踐demo中配置自動(dòng)化測試的基本步驟。Espresso setup instructions
1. 在gradle添加支持
在app目錄下build.gradle中dependencies設(shè)置對Espresso庫的編譯依賴,在android.defaultConfig設(shè)置InstrumentationRunner。
// 在app目錄下的build.gradle添加對Espresso的依賴
dependencies {
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.espresso:espresso-idling-resource:2.2.2'
...
}
// 在app目錄下的build.gradle中設(shè)置instrumentation runner
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
2. 創(chuàng)建Test Case文件
在Android Studio執(zhí)行測試的代碼類文件需要在app模塊的androidTest文件夾下創(chuàng)建。如下圖所示:

3. 編寫測試用例代碼
比如當(dāng)我們?yōu)門estActivity創(chuàng)建TestActivityTest測試用例類文件成功以后:
- 首先需要在測試用例類的類體前添加@RunWith的注解,并設(shè)置測試運(yùn)行平臺(tái)為AndroidJUnit4
- 如果允許測試需要較大消耗,可以使用@LargeTest注解
- 設(shè)置ActivityTestRule用來指明被測試的Activity,使用@Rule注解。
運(yùn)行測試時(shí)用例時(shí)會(huì)自動(dòng)啟動(dòng)到對應(yīng)的Activity,并且通過ActivityTestRule的示例獲取到被測試Activity的context。
- 編寫測試方法,按照前面說的“找元素,做操作, 驗(yàn)證結(jié)果”三個(gè)步驟編 寫測試方法,使用@Test注解。
建議使用test作為方法名的開頭,這樣可以更好區(qū)分普通方法和測試方法

如上圖所示,代碼為TestActivity創(chuàng)建了測試用例類TestActivityTest,其中testDeciceName為其中一個(gè)測試用例方法。該方法主要是通過id查找到EditText,自動(dòng)輸入內(nèi)容后模擬點(diǎn)擊id為bt_get_string的button,最后驗(yàn)證textview顯示內(nèi)容是否符合。
4. 運(yùn)行Test Case
在Android Studio的終端中輸入gradlew connectedAndroidTest 或 gradlew cAT執(zhí)行測試用例。
整體運(yùn)行效果如下:

5. 異步和延遲
有時(shí)點(diǎn)擊一個(gè)按鈕,ui操作后需要執(zhí)行一個(gè)較為耗時(shí)的事情時(shí)通常會(huì)采用異步回調(diào)的方式通知顯示結(jié)果,這時(shí)進(jìn)行UI自動(dòng)化測試的第三步驗(yàn)證結(jié)果的時(shí)機(jī)就不能才能同步的方式去執(zhí)行,而是需要做異步回調(diào)通知執(zhí)行或延遲執(zhí)行。
Espresso提供了原生的異步測試支持,通過實(shí)現(xiàn)IdlingResource接口,復(fù)寫getName()、isIdleNow()、registerIdleTranstionCallback()方法。
如圖所示FuncExecuteIdlingResource:

然后在測試用例的類中注冊和反注冊接口:
Espresso.registerIdlingResources(idlingResource);

當(dāng)方法執(zhí)行完成,調(diào)用ResourceCallback.onTransitionToIdle();則會(huì)進(jìn)行回調(diào)通知測試線程繼續(xù)執(zhí)行驗(yàn)證代碼。
總結(jié)
一切能自動(dòng)化完成的測試操作就不要浪費(fèi)時(shí)間用手動(dòng)完成。后續(xù)將會(huì)對單元測試進(jìn)行說明,共同學(xué)習(xí),相互提升。