Android Studio下單元測試的本質(zhì)其實(shí)是根據(jù)通過書寫JAVA測試代碼放航,通過模擬用戶調(diào)用相應(yīng)的方法置鼻,或者使用者按下相應(yīng)的按鍵來驗(yàn)證我們的代碼的邏輯是否能達(dá)到預(yù)期的要求,如果所有的用例都能通過丹壕,則證明我們的邏輯滿足要求庆械,否則,可以通過fail()函數(shù)(或使用Assert)進(jìn)行輸出錯誤信息菌赖。
在進(jìn)行測試前我們首先需要了解一下幾個基本的概念:TestCase缭乘,TestSuite:
如圖1所示,TestSuite和TestCase都是繼承自Test接口琉用,同時,TestSuite的建立和使用依賴于TestCase實(shí)例邑时,TestCase繼承自Assert類奴紧,因此TestCase中可以直接使用Assert中的相關(guān)方法,Assert類提供了幾個常用的判斷方法,Assert的類圖可以參照圖2:
TestCase:
在進(jìn)行單元測試的時候晶丘,在JUNIT4之前黍氮,我們需要測試的代碼所在的類一般都需要直接或者間接繼承自TestCase,對于我們創(chuàng)建的這個TestCase的子類浅浮,我們需要注意在我們這個類的測試流程沫浆,假設(shè)我們創(chuàng)建的TestCase子類中有兩個測試用例testMethod1和testMethod2,則執(zhí)行順序可以如圖3所示:
對于我們類中的兩個測試用例testMethod1和testMethod2滚秩,都會分別創(chuàng)建一個新的TestCase子類對象专执,并引起TestCase中的setUp和tearDown函數(shù)分別執(zhí)行一遍,因此郁油,在進(jìn)行單元測試的過程中本股,我們可以在setUp當(dāng)中進(jìn)行一些初始化操作(如類的某些屬性的賦值操作),在tearDown中進(jìn)行一些掃尾工作(如類中某些對象所持有資源的釋放)桐腌。
一個簡單的Demo:
import junit.framework.TestCase;
public class TestDemo extends TestCase{
@Override
protected void setUp() throws Exception {
// TODO Auto-generated method stub
super.setUp();
System.out.println("setUp , hashCode = "+hashCode());
}
@Override
protected void tearDown() throws Exception {
// TODO Auto-generated method stub
super.tearDown();
System.out.println("tearDown,hashCode = "+hashCode());
}
public void testMethod1(){
System.out.println("testMethod1 , hashCode = "+hashCode());
}
public void testMethod2(){
System.out.println("testMethod2 , hashCode = "+hashCode());
}
}
運(yùn)行結(jié)果拄显,如圖4所示:
有兩個test函數(shù),testMethod1和testMethod2案站,在生命周期的開始函數(shù)setUp以及結(jié)尾函數(shù)tearDown中分別產(chǎn)生了兩次不同的hashCode躬审,根據(jù)Java語言中HashCode的概念我們可以知道這分別導(dǎo)致了我們的TestDemo類型的對象創(chuàng)建了兩次。因此如果測試的case增多,我們的TestDemo對象也會創(chuàng)建和case相同的個數(shù)盒件。
對于測試用例testMethod1和testMethod2的函數(shù)聲明,在我們書寫用例函數(shù)的時候需要注意他們有一個共同的特點(diǎn):
1).訪問權(quán)限都是public舱禽;
2).返回類型都是void;
3).沒有參數(shù)炒刁;
4).方法名以“test”開頭。
在使用單元測試的時候必須注意用例方法的生命格式誊稚,否則該用例將不會被執(zhí)行的到翔始。
TestSuite:
對于suite這個英文單詞,從字面上可以理解為組合或者集合的意思里伯,再加上通過圖1城瞎,我們發(fā)現(xiàn)TestSuite和TestCase都是實(shí)現(xiàn)自Test接口,這很容易讓我們想起JAVA設(shè)計模式中的合成模式的概念:即TestSuite可以認(rèn)為合成模式中的組疾瓮,是一組TestCase對象的集合脖镀;而TestCase對象時這個合成模式中的葉子對象,并且狼电,這些TestCase對象(葉子對象)和TestSuite(組對象)擁有共同的行為(run方法)蜒灰;這樣,可以保證當(dāng)用戶調(diào)用組對象TestSuite的run方法的時候肩碟,也會調(diào)用到TestCase對象的run方法强窖。而事實(shí)上也確實(shí)是這樣,在使用JUnit3執(zhí)行測試的過程中削祈,會首先創(chuàng)建TestSuite對象翅溺,在TestSuite對象的構(gòu)造方法中,會掃描TestCase子類的所有方法髓抑,并調(diào)用addTestMethod方法咙崎,在該方法中調(diào)用isPublicTestMethod方法判斷是否是待測的方法,若是會調(diào)用createTest方法启昧,創(chuàng)建一個Test對象叙凡,并調(diào)用addTest方法加入到自己的集合中去,因此執(zhí)行過程中的TestCase子類都會以具體的test方法個數(shù)創(chuàng)建自身實(shí)例的個數(shù)密末,并加入到TestSuite中握爷,TestSuite的相對詳細(xì)的類圖如圖5所示:
一個簡單的例子了解一下TestSuite:
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class TestSuiteDemo extends TestSuite{
public static Test suite(){
//創(chuàng)建TestSuite對象
TestSuite suite = new TestSuite();
//為TestSuite添加一個測試用例集合,參數(shù)為:ClasstestClass
//通過參數(shù)可以知道严里,其實(shí)該參數(shù)就是TestCase的子類
suite.addTestSuite(TestDemo.class);
//創(chuàng)建具體的測試用例
Test test = TestSuite.createTest(TestDemo.class, "testMethod1");
//添加一個具體的測試用例
suite.addTest(test);
return suite;
}
}
執(zhí)行結(jié)果如圖6:
通過代碼和運(yùn)行結(jié)果新啼,我們可以看出testMethod1執(zhí)行了兩次而testMethod2只執(zhí)行了一次,通過分析上述代碼得出testMethod1執(zhí)行兩次的原因是:第一次是在addTestSuite的時候?qū)⑵渥鳛橐粋€測試用例傳入到TestSuite中刹碾,第二次是通過addTest方法將用例加入到TestSuite中燥撞,因此在執(zhí)行的時候?qū)⑵鋱?zhí)行了兩遍,通過比較hashCode得出總共創(chuàng)建了三個TestCase對象的結(jié)論。
通過上述代碼物舒,我們需要強(qiáng)調(diào)一下色洞,如果我們想一次執(zhí)行一組TestCase實(shí)現(xiàn)類的測試,這個時候可以自定義TestSuite對象冠胯,將需要測試的TestCase實(shí)現(xiàn)類加入到TestSuite中去火诸。我們需要了解TestSuite如何使用,其實(shí)TestSuite的使用也很簡單荠察,在TestSuite的使用的時候置蜀,我們必須在TestSuite的實(shí)現(xiàn)類中,自定義suite方法悉盆,由于suite方法會通過反射調(diào)用,反射調(diào)用代碼如下:
public static Test testFromSuiteMethod(Classklass) throws Throwable {
Method suiteMethod= null;
Test suite= null;
try {
suiteMethod= klass.getMethod("suite");
if (! Modifier.isStatic(suiteMethod.getModifiers())) {
throw new Exception(klass.getName() + ".suite() must be static");
}
suite= (Test) suiteMethod.invoke(null); // static method
} catch (InvocationTargetException e) {
throw e.getCause();
}
return suite;
}
所以suite方法命名規(guī)則如下:
1).必須以“suite”方法命名焕盟;
2).suite方法的訪問修飾權(quán)限必須為static秋秤;
3).suite方法必須為靜態(tài)方法;
4).suite方法必須沒有參數(shù)脚翘。
總結(jié):
TestCase和TestSuite類是JUNIT中比較重要的兩個類航缀,TestCase和TestSuite可以認(rèn)為是JAVA的合成設(shè)計模式在單元測試中的應(yīng)用,其實(shí)即便我們沒有自己聲明和創(chuàng)建TestSuite的子類堰怨,而且運(yùn)行的TestCase子類的過程中也會創(chuàng)建TestSuite類芥玉,并將要執(zhí)行的TestCase子類的實(shí)例對象添加到TestSuite中去執(zhí)行,其執(zhí)行過程可以如圖7所示:
在選擇JUnit執(zhí)行引擎的時候备图,便創(chuàng)建了TestSuite對象灿巧,并通過上面介紹TestSuite介紹過的addTestMethod,creatTest揽涮,addTest方法抠藕,將要測的TestCase類中的所有測試用例給掃描出來,并添加到待測列表中去蒋困。在執(zhí)行JUnit測試引擎的run方法時會調(diào)用TestSuite的的run方法盾似,TestSuite在執(zhí)行自身run方法時會遍歷所有TestCase對象的run方法,同一個TestCase子類的run方法會根據(jù)自身所包含的測試用例個數(shù)被執(zhí)行相應(yīng)的次數(shù)雪标。