1.前言
應(yīng)用測(cè)試是每個(gè)程序員的基本功,目的是為了保證自己寫的代碼的正確性。公司一般都有專門的測(cè)試人員,他們負(fù)責(zé)對(duì)整個(gè)應(yīng)用或功能模塊進(jìn)行測(cè)試。兩者之間有什么區(qū)別呢?這得從測(cè)試的目的說(shuō)起。
測(cè)試是為了避免開(kāi)發(fā)過(guò)程中的問(wèn)題所帶來(lái)的風(fēng)險(xiǎn),本著越早發(fā)現(xiàn)越早解決,這樣可以減少修改時(shí)所需要的代價(jià)。舉個(gè)例子,測(cè)試人員在應(yīng)用上線前測(cè)出Bug,需要在整個(gè)應(yīng)用所有模塊中,定位到有問(wèn)題的地方,將錯(cuò)誤現(xiàn)象告知相應(yīng)開(kāi)發(fā)人員去修改,然后再次合并打包成完整應(yīng)用。這個(gè)過(guò)程僅消耗的時(shí)間,就比開(kāi)發(fā)人員完成邏輯后,按照文檔進(jìn)行測(cè)試,再合并打包的時(shí)間要長(zhǎng),所以開(kāi)發(fā)人員懂得測(cè)試是很重要的。
2.測(cè)試支持庫(kù)
Google提供了測(cè)試支持庫(kù),詳細(xì)信息參考官網(wǎng)支持庫(kù)。其中AndroidJUnitRunner類是JUnit測(cè)試運(yùn)行器,可在Android設(shè)備上運(yùn)行JUnit 3或JUnit 4樣式的測(cè)試類(不能混合使用),包括使用Espresso和UI Automator測(cè)試框架的設(shè)備。測(cè)試運(yùn)行器可以將測(cè)試軟件包和被測(cè)試的應(yīng)用一起加載到設(shè)備、運(yùn)行測(cè)試并報(bào)告測(cè)試結(jié)果,如下圖所示:

3.測(cè)試的分類
根據(jù)AndroidJUnitRunner的作用可以將測(cè)試分為兩大類,一類運(yùn)行在計(jì)算機(jī)本地Java虛擬機(jī)(JVM)上,另一類運(yùn)行在硬件設(shè)備或模擬器上。官方給出的分類是(詳見(jiàn) Android Studio用戶指南):
- 本地單元測(cè)試。當(dāng)測(cè)試沒(méi)有Android框架依賴項(xiàng)或使用Mockito之類的庫(kù)模擬Android框架依賴項(xiàng)時(shí),可以利用此類測(cè)試來(lái)盡量縮短執(zhí)行時(shí)間。JUnit測(cè)試就是最佳代表,它用于測(cè)試功能的正確性,通過(guò)斷言進(jìn)行驗(yàn)證。
模塊級(jí)build.gradle需要依賴的庫(kù)文件:
dependencies {
// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'
// Optional -- Mockito framework
testCompile 'org.mockito:mockito-core:1.10.19'
}
IDE提供的最簡(jiǎn)單的測(cè)試:
import org.junit.Test;
import static org.junit.Assert.*;
// 這是測(cè)試示例
public class ExampleUnitTest {
// 1.通過(guò)注解標(biāo)明測(cè)試方法的生命周期
@Test
public void addition_isCorrect() throws Exception {
// 2.調(diào)用不涉及Android框架的邏輯代碼
int sum = 2 + 2;
// 3.通過(guò)斷言判斷對(duì)錯(cuò)
assertEquals(4, sum);
}
}
- 設(shè)備測(cè)試。按有權(quán)訪問(wèn)的類型,將測(cè)試分為兩類。
第一類是設(shè)備單元測(cè)試,有權(quán)訪問(wèn)Instrumentation API,可以獲取某些信息(例如,被測(cè)試應(yīng)用的Context),并且允許通過(guò)測(cè)試代碼來(lái)控制受測(cè)應(yīng)用。
第二類是自動(dòng)化UI測(cè)試,有權(quán)訪問(wèn)UI組件,可以編寫集成和功能UI測(cè)試來(lái)自動(dòng)化用戶交互,可以解決模擬對(duì)象無(wú)法滿足的部分Android依賴項(xiàng)。
由于自動(dòng)化UI測(cè)試依賴于設(shè)備單元測(cè)試,所以一起說(shuō)一下基本操作(在模塊級(jí)build.gradle中進(jìn)行)。
首先,需配置運(yùn)行器:
android {
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
接著,需要依賴相應(yīng)的支持庫(kù):
dependencies {
// Required -- JUnit 4 test runner
androidTestCompile 'com.android.support.test:runner:0.5'
// Optional -- solve a dependency conflict with support-annotations
androidTestCompile 'com.android.support:support-annotations:24.0.0'
// Optional -- JUnit 4 test rules
androidTestCompile 'com.android.support.test:rules:0.5'
// Optional -- Hamcrest library
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
// Optional -- UI testing with Espresso
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
// solve a dependency conflict with support-annotations
exclude group: 'com.android.support', module: 'support-annotations'
})
// Optional -- UI testing with UI Automator
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}
最后,通過(guò)設(shè)備單元測(cè)試調(diào)用Android框架 API,進(jìn)行基本邏輯驗(yàn)證;而通過(guò)Espresso庫(kù)提供的方法訪問(wèn)視圖,進(jìn)行交互操作;UI Automator最為強(qiáng)大,除了可以與自己應(yīng)用交互,還可以與系統(tǒng)交互,完全模仿用戶操作,不需要知道應(yīng)用內(nèi)部實(shí)現(xiàn)。詳細(xì)使用方式,請(qǐng)參考官方培訓(xùn)。
4.源集的概念
由于設(shè)備測(cè)試內(nèi)置于APK中(與被測(cè)試的應(yīng)用APK分離),因此可能需要擁有自己的AndroidManifest.xml文件來(lái)指定最小版本號(hào)(除UI Automator需要API 18,其它為API 8以上即可)和注冊(cè)測(cè)試專用的運(yùn)行偵聽(tīng)器。構(gòu)建應(yīng)用時(shí),Gradle會(huì)將多個(gè)清單文件合并成一個(gè)清單,先來(lái)分析一下里面的邏輯。

開(kāi)發(fā)過(guò)Android的都知道,若新建一個(gè)項(xiàng)目,它的工程結(jié)構(gòu)默認(rèn)只包含app主模塊。在模塊的src目錄下,每個(gè)文件夾都是一個(gè)源集(對(duì)應(yīng)構(gòu)建的特定應(yīng)用版本),存放著代碼和資源,而共用的部分就放在系統(tǒng)默認(rèn)的main源集下。
源集的名稱由兩個(gè)可缺省的部分組成(src/<productFlavorBuildType>/),前半部分為產(chǎn)品風(fēng)味,因?yàn)槊總€(gè)渠道都有自己的特色,所以基本上以渠道命名;后半部分為構(gòu)建類型,在上圖中就是androidTest、test,分別表示設(shè)備測(cè)試和本地單元測(cè)試。尤其注意,所有測(cè)試均針對(duì)debug構(gòu)建類型運(yùn)行,若想修改參考如下代碼(位于模塊級(jí)build.gradle文件):
android {
...
testBuildType "staging"
}
應(yīng)用構(gòu)建時(shí)需要將特定的源集與main合并,具體由Gradle配置文件決定。如果不同源集包含同一文件的不同版本,Gradle將按以下優(yōu)先順序決定使用哪一個(gè)文件(左側(cè)源集替換右側(cè)源集的文件和設(shè)置):構(gòu)建變體 (含有風(fēng)味與類型)> 構(gòu)建類型 > 產(chǎn)品風(fēng)味 > main源集 > 庫(kù)依賴項(xiàng)。這樣一來(lái),Gradle便可使用專用的構(gòu)建文件,同時(shí)對(duì)與其他應(yīng)用版本共用的Activity、應(yīng)用邏輯和資源加以重復(fù)利用。
在合并多個(gè)清單文件時(shí),Gradle使用同一優(yōu)先順序,使每個(gè)構(gòu)建過(guò)程都能在最終清單中定義不同的組件或權(quán)限。
5.總結(jié)
除了以上測(cè)試外,還有其它類型的測(cè)試,比如壓力測(cè)試等。這篇文章旨在說(shuō)明測(cè)試方法之間的邏輯聯(lián)系、依賴關(guān)系以及適用場(chǎng)景等,具體使用方法會(huì)單獨(dú)講解。若急于入門,可以看看fodroid的文章。