這章就先來說說android中單元測(cè)試的操作,簡(jiǎn)單走一遍單元測(cè)試的流程。
為什么要用到單元測(cè)試呢,一般開發(fā)誰會(huì)寫單元測(cè)試,反正我認(rèn)識(shí)的人都不會(huì)做,又耗時(shí)間,效果又一般,要是在單元測(cè)試的代碼里面又出BUG的話又要改半天,麻煩。
但是有的時(shí)候真的是不得不用,比如說你有一步邏輯操作,你想去判斷這邏輯操作是否正確。但是運(yùn)行這步操作之前有10步操作,然后這個(gè)邏輯操作的情況一共有10種(舉個(gè)比較極端的栗子)。那如果你運(yùn)行Debug檢驗(yàn)每一種情況的時(shí)候,都需要每種情況先執(zhí)行10步操作才能驗(yàn)證,那就很麻煩啊。
所以這時(shí)候你可能就會(huì)需要用到單元測(cè)試,直接對(duì)單步操作進(jìn)行測(cè)試,也不用把整個(gè)項(xiàng)目都跑起來,直接對(duì)特定的方法進(jìn)行測(cè)試。
但說句實(shí)在話,雖然開發(fā)流程中規(guī)定要進(jìn)行單元測(cè)試。但這單元測(cè)試誰來做,還不是研發(fā)來做,我們代碼平時(shí)都很趕,還有什么時(shí)間去寫單元測(cè)試的邏輯和用例,所以我覺得僅僅對(duì)某部分base庫或者重要的邏輯做測(cè)試就夠了。
一.搭建環(huán)境
搭建環(huán)境很簡(jiǎn)單,在gradle中添加依賴
testImplementation 'org.mockito:mockito-core:2.25.1'
版本號(hào)肯定不是固定的,可以直接在File-Project Structure中查找這個(gè)庫,這樣肯定是最新版本,不過要記得把implementation變成testImplementation 。
然后我們創(chuàng)建相應(yīng)的測(cè)試類,也很簡(jiǎn)單,以前我是手動(dòng)創(chuàng)建的,之前get到別人的一招。
光標(biāo)放到你想測(cè)的類的類名,然后alt + enter , 選擇Create Test

自動(dòng)會(huì)幫你填好name,你想改也行,下面可以選before和after,就是你想在測(cè)試前和測(cè)試后做的操作的方法。再下面Member可惜選著對(duì)應(yīng)的方法。
選擇好之后點(diǎn)擊OK,然后會(huì)讓你選擇androidTest下還是test下,默認(rèn)創(chuàng)建android項(xiàng)目不是幫你創(chuàng)建3個(gè)文件夾嘛

我們因?yàn)槭侵粚?duì)某個(gè)方法做測(cè)試,所以選擇test(兩個(gè)文件夾的區(qū)別以后再說)。
二.單元測(cè)試
假如我想測(cè)一個(gè)功能,就測(cè)我以前寫的那個(gè)Gson解析泛型的功能吧。
public T getDataContent(String jsondata){
Gson gson = new Gson();
Type type = getClass().getGenericSuperclass();
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
Type ty = new ParameterizedTypeImpl(BaseResponse.class, new Type[]{types[0]});
BaseResponse<T> data = gson.fromJson(jsondata, ty);
return data.content;
}
看看BaseResponse
public class BaseResponse<T> {
public String ret;
public String msg;
public T content;
}
因?yàn)檫@個(gè)是一個(gè)很重要的功能,每個(gè)地方的網(wǎng)絡(luò)請(qǐng)求都會(huì)走這段代碼,所以我要測(cè)試它,看看不同的情況是否能得到我想要的結(jié)果。
按照上面的做法生成一個(gè)測(cè)試的類和方法
public class HttpCallBackTest {
@Test
public void getDataContent(){
}
}
可以發(fā)現(xiàn)在androidstudio里面,getDataContent方法左邊有個(gè)運(yùn)行按鈕,點(diǎn)擊就可以單獨(dú)對(duì)這個(gè)方法進(jìn)行測(cè)試。
現(xiàn)在我們要測(cè)試這個(gè)功能,那么就需要寫測(cè)試用例,假如我這邊寫4個(gè)測(cè)試用例看看能不能都成功解析,4個(gè)json字符串(在代碼里面加了換行符所以可能有點(diǎn)難看)。
String mockData = "{\n" +
"\t\"ret\":\"1\",\n" +
"\t\"msg\":\"success\",\n" +
"\t\"content\":{\n" +
"\t\t\"id\":\"10000\",\n" +
"\t\t\"sex\":\"男\(zhòng)",\n" +
"\t\t\"age\":18\n" +
"\t}\n" +
"}";
String mockData2 = "{\n" +
"\t\"ret\":\"1\",\n" +
"\t\"msg\":\"success\",\n" +
"\t\"content\":[\n" +
"\t\t{\n" +
"\t\t\t\"id\":\"10000\",\n" +
"\t\t\t\"sex\":\"男\(zhòng)",\n" +
"\t\t\t\"age\":\"18\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"id\":\"10001\",\n" +
"\t\t\t\"sex\":\"女\",\n" +
"\t\t\t\"age\":\"16\"\n" +
"\t\t}\n" +
"\t]\n" +
"}";
String mockData3 = "{\n" +
"\t\"ret\":\"1\",\n" +
"\t\"msg\":\"success\",\n" +
"\t\"content\": \"aaa\"\n" +
"}";
String mockData4 = "{\n" +
"\t\"ret\":\"1\",\n" +
"\t\"msg\":\"success\",\n" +
"\t\"content\": []\n" +
"}";
寫個(gè)對(duì)象來接收
public static class TestData{
public String id;
public String sex;
public int age;
}
現(xiàn)在來寫測(cè)試的代碼
(1)第一個(gè)測(cè)試用例
@Test
public void getDataContent(){
httpCallBack = new HttpCallBack<TestData>();
TestData testData = (TestData) httpCallBack .getDataContent(mockData);
assertEquals("10000",testData.id);
assertEquals("男",testData.sex);
assertEquals(18,testData.age);
}
測(cè)試用到的assertEquals方法,這個(gè)之后會(huì)詳細(xì)講。
可以看到下邊會(huì)有打印 Process finished with exit code 0 說明測(cè)試通過,如果不通過會(huì)顯示詳細(xì)的不通過的信息。
比如說我寫的 assertEquals(12,testData.age); ,錯(cuò)誤的情況會(huì)提示

如果是代碼錯(cuò)誤的話也會(huì)報(bào)出詳細(xì)的Exception信息。
(2)第二個(gè)測(cè)試用例
@Test
public void getDataContent(){
httpCallBack = new HttpCallBack<Lits<TestData>>();
Lits<TestData> testDatas = (Lits<TestData>) httpCallBack .getDataContent(mockData2);
assertEquals("女",testDatas.get(1).sex);
}
(3)第三個(gè)測(cè)試用例
@Test
public void getDataContent(){
httpCallBack = new HttpCallBack<String>();
String testData = (String ) httpCallBack .getDataContent(mockData3);
assertEquals("aaa",testData);
}
(4)第四個(gè)測(cè)試用例
@Test
public void getDataContent(){
httpCallBack = new HttpCallBack<Lits<TestData>>();
Lits<TestData> testDatas = (Lits<TestData>) httpCallBack .getDataContent(mockData4);
assertEquals(0,testDatas.size());
}
4個(gè)用例如果都通過,說明我這個(gè)解析json泛型的方法基本不會(huì)有問題。
當(dāng)然,可以把4種情況都寫在一起,這樣就只用跑一次,我這里是為了看清楚點(diǎn)所有分開寫。
這樣就是一個(gè)簡(jiǎn)單的單元測(cè)試的流程。
三.assert
從上面可以看出最主要判斷測(cè)試正確和錯(cuò)誤的方法是用assert(斷言)。
而這些方法都是屬于Assert類,大概的斷言方法有這些

其中 assertThat 是一個(gè)比較高級(jí)的用法,這個(gè)以后再說,不過我個(gè)人基本是沒有用過assertThat ,單單其它的幾個(gè)方法基本就夠用了。
四.補(bǔ)充
可能有的朋友有些時(shí)候覺得測(cè)一個(gè)類難以下手,比如還是我說的解析代碼,你是這樣寫的。
public void requestFinish(String jsonData){
......
......
Gson gson = new Gson();
Type type = getClass().getGenericSuperclass();
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
Type ty = new ParameterizedTypeImpl(BaseResponse.class, new Type[]{types[0]});
BaseResponse<T> data = gson.fromJson(jsondata, ty);
// 假如用回調(diào)的方式
callback.finish(data.content);
......
}
比如這樣,要怎么斷言,我這個(gè)方法中又不僅僅只有解析的代碼,還有其他的代碼,而且我這個(gè)方法是一個(gè)void方法,不像上面一樣有返回值的。
其實(shí)很簡(jiǎn)單,要不然就判斷這個(gè)方法的外層那個(gè)方法,要不然就像我一樣單獨(dú)把那塊功能代碼抽出來。我是建議抽出來,也符合單一職權(quán)。
這篇文章就這樣吧,主要是講講什么時(shí)候用到單元測(cè)試的心得,然后簡(jiǎn)單說一下測(cè)試的一個(gè)流程。至于更為復(fù)雜的用法,我自己現(xiàn)在都用不到,如果用上了,以后再講。