在軟件測試過程中卢鹦,單元測試屬于早期的測試活動锻离,一般由開發(fā)人員完成,但測試人員也會參與槽棍。在單元測試活動中捉蚤,強調(diào)軟件單元的獨立性,即在被測單元與程序的其他部分相隔離的情況下完成測試炼七。
單元測試的重要性在于它是軟件測試的基礎(chǔ)缆巧,單元測試的效果直接影響到軟件的后期測試,最終在很大程度上影響到產(chǎn)品的質(zhì)量豌拙。越早發(fā)現(xiàn)缺陷陕悬,解決缺陷的成本就越低,而且在單元測試時按傅,某些問題很容易被發(fā)現(xiàn)捉超,如果將這些問題留到后期,測試的成本和風險將成倍上升唯绍。單元測試始終追求的目標是盡早地發(fā)現(xiàn)與解決問題拼岳,從而保證產(chǎn)品的質(zhì)量。
JUnit測試框架
JUnit是一個開源的Java測試框架况芒,用于構(gòu)建可重復的單元測試惜纸,可以看作單元測試框架體系xUnit的一個實例,主要特性有:
1) 用于測試期望結(jié)果的斷言绝骚;
2)用于共享共同測試數(shù)據(jù)的測試工具耐版;
3) 用于方便地組織和運行測試的測試套件。
JUnit的源代碼是公開的压汪,可以針對特定需求進行二次開發(fā)粪牲,而且JUnit具有很強的擴展性,使之具有良好的適應性止剖。除此之外腺阳,JUnit還具有下列優(yōu)點:
4) 可以使測試代碼與產(chǎn)品代碼分開湿滓,有利于代碼的打包發(fā)布和測試代碼的管理;
5) 針對某一個類的測試代碼舌狗,做較少的改動便可以應用于另一個類的測試叽奥,JUnit提供了一個編寫測試類的框架,使測試代碼的編寫更加方便痛侍;
6) 易于集成到程序構(gòu)建過程中朝氓,如通過和Ant的結(jié)合實現(xiàn)持續(xù)集成和持續(xù)測試。
JUnit一共有7個包主届,其核心的包是JUnit.framework和JUnit.runner赵哲。framework包負責整個測試對象的構(gòu)建,runner負責測試驅(qū)動君丁。JUnit還包括4個重要的類:TestSuite枫夺、TestCase、TestResult和TestRunner绘闷。另外橡庞,JUnit還包括Test和TestListener接口、Assert類印蔗。
1) Assert類用來驗證條件是否成立扒最,當條件成立時,assert方法保持沉默华嘹;若條件不成立時就拋出異常吧趣。Assert超類提供8個核心方法,見下表耙厚。
2) Test接口類用來測試和收集測試的結(jié)果强挫,采用了Composite設(shè)計模式,它是單獨的測試用例薛躬、聚合的測試模式及測試擴展的共同接口俯渤。
3) TestCase抽象類用來定義測試中的固定方法,TestCase是Test接口的抽象實現(xiàn)泛豪。由于TestCase是一個抽象類稠诲,因此不能被實例化侦鹏,只能被繼承诡曙。其構(gòu)造函數(shù)可以根據(jù)輸入的測試名稱來創(chuàng)建一個測試用例,提供測試名稱的目的在于方便測試失敗時查找失敗的測試用例略水。
4) TestSuite是由幾個TestCase或其他的TestSuite構(gòu)成的价卤。基于TestSuite可輕松構(gòu)建一個樹形測試渊涝,每個測試都由持有另外一些測試的TestSuite來構(gòu)成慎璧。加入到TestSuite中的測試在一個線程上依次被執(zhí)行床嫌。
5) TestResult負責收集TestCase所執(zhí)行的結(jié)果并將結(jié)果分類,分為客戶可預測的錯誤和沒有預測的錯誤胸私。它還將測試結(jié)果轉(zhuǎn)發(fā)給TestListener處理厌处。
6) TestRunner是客戶對象調(diào)用的起點,它跟蹤整個測試過程岁疼,能夠顯示測試結(jié)果阔涉,并且報告測試的進度。
7) TestListenter對測試結(jié)果的處理和測試驅(qū)動過程的工作特征進行提取捷绒,包含4個方法:addError()瑰排、addFailuer()、startTest()和endTest()暖侨。
TestNG與JUnit比較
TestNG是一個不錯的測試框架椭住,尤其是在進行模塊測試和大范圍的測試時,它比JUnit更靈活字逗。JUnit4推出后京郑,其很多功能都與TestNG相似,但相對于JUnit4葫掉,TestNG還有較大的差異傻挂。
1. 靈活性
同JUnit4一樣,TestNG同樣支持Before挖息、After方法金拒,如同setUp和tearDown。不過套腹, TestNG更靈活绪抛,支持各種簽名方式,如private电禀、protected等幢码,其代碼如下:
? ? @BeforeMethod
? ? protected void beforeMethod() {
? ? ? System.out.println("in beforeMethod");
? ? }
? ? @AfterMethod
? ? protected void afterMethod() {
? ? ? System.out.println("in afterMethod");
? ? }
TestNG同樣也支持BeforeClass和AfterClass,只執(zhí)行一次的方法尖飞,但是可以不須要使用static簽名症副,其代碼如下:
? ? @BeforeClass
? ? protected void beforeClassMethod() {
System.out.println("in beforeClassMethod");
? ? }
? ? @AfterClass
? ? protected void afterClassMethod() {
? System.out.println("in afterClassMethod");
? ? }
JUnit框架想達到的一個目的就是測試隔離,導致人們很難確定測試用例執(zhí)行的順序政基,而這對于各種依賴性測試又非常重要贞铣。雖然人們想出了多種方法來解決這個問題,例如沮明,按字母順序指定測試用例辕坝,或者依靠fixture來解決問題。
與JUnit不同荐健,TestNG利用“Test注釋”的dependsOnMethods屬性可以很容易地處理測試的依賴性問題酱畅。例如琳袄,testMethod2依賴于testMethod1,可以描述如下:
? ? @Test
? ? public void testMethod1() {
? ? ? System.out.println("in testMethod1");
? ? }
@Test(dependsOnMethods="testMethod1")
? ? public void testMethod2() {
? ? ? System.out.println("in testMethod2");
? ? }
當然如果testMethod1失敗纺酸,默認testMethod2也不會執(zhí)行窖逗。不過,只須設(shè)置alwaysRun =true餐蔬,則若testMethod1失敗滑负,可以跳過testMethod1,而執(zhí)行testMethod2用含,描述如下:
? ? @Test
? ? public void testMethod1() {
? ? ? System.out.println("in testMethod1");
? ? ? throw new RuntimeException("failed");
? ? }
@Test(dependsOnMethods="testMethod1",alwaysRun = true)
? ? public void testMethod2() {
? ? ? System.out.println("in testMethod2");
? ? }
3. 重新運行未通過的測試
在大量的測試用例執(zhí)行中矮慕,這種重新運行失敗測試的能力顯得尤為重要。這也是TestNG的優(yōu)勢啄骇。在JUnit 4中痴鳄,如果測試套件包括1000項測試,其中3項失敗了缸夹,修改錯誤以后痪寻,很可能不得不重新運行整個測試套件,會多耗費幾個小時虽惭。
TestNG在執(zhí)行中一旦出現(xiàn)失敗橡类,就會自動創(chuàng)建一個XML配置文件(一般命名為testng-failed.xml),對失敗的測試加以說明芽唇。如果利用這個文件執(zhí)行TestNG運行程序顾画,就只運行失敗的用例,而不是整個測試套件匆笤。同時研侣,要求用例解耦。
4. 參數(shù)化測試
另一個有趣的TestNG特性是參數(shù)化測試炮捧。在JUnit中庶诡,如果想改變某個受測方法的參數(shù)組,就只能給每個不同的參數(shù)組編寫一個測試用例咆课。多數(shù)情況下末誓,這不會帶來太多麻煩。然而书蚪,我們有時會碰到一些情況喇澡,如其中的業(yè)務(wù)邏輯,要運行的測試數(shù)目變化范圍很大善炫。
TestNG可在XML配置文件中放入?yún)?shù)化數(shù)據(jù)撩幽,從而對不同的數(shù)據(jù)集重用同一個測試用例,這樣可以對輸入數(shù)據(jù)進行充分的測試箩艺,包括邊界條件或無效數(shù)據(jù)的保護性驗證測試窜醉。
完整的軟件開發(fā)過程示例
假定須要實現(xiàn)字符串刪除功能(將一段字符串中出現(xiàn)的所有某個單詞全部刪除掉),在已有類StringUtil.java中編程如圖所示艺谆。
1) 為源代碼編寫測試程序
寫好程序源代碼之后榨惰,在對應的測試文件中,加上testDeleteString方法静汤,其代碼如圖所示琅催。這里只是在一個已有的測試類中添加一個測試方法。
采用3個case組合的目的是為了讓源程序中的3種case都能被執(zhí)行到虫给,以提高測試代碼的覆蓋率藤抡。
2) 調(diào)試程序跟蹤中間結(jié)果
2.1) 設(shè)置斷點
只須雙擊設(shè)置斷點的代碼行的行號即可。例如在65行與69行前設(shè)置斷點抹估。如果在已設(shè)置好斷點的行號前再次雙擊缠黍,斷點就會取消。
2.2) 開始調(diào)試
右擊須要進行調(diào)試的類名药蜻,這里是StringUtilTest.java瓷式。選擇“Debug As”→“Open Debug Dialog…”,在彈出的窗口中檢驗是否為待調(diào)試的類语泽,然后單擊Debug贸典。
3). 結(jié)果分析
查看中間結(jié)果。如果有錯誤踱卵,可以修改源程序或修改測試程序廊驼,直到完全正確。程序會首先停止在設(shè)置的斷點上(本例為65行)惋砂,然后按F6功能鍵蔬充,逐步執(zhí)行,每步執(zhí)行一行班利〖⒙可以在右上角Variable變量欄列表中看到每個變量運行時的值的變化情況,非常方便罗标。從下圖可以清楚地看到庸队,程序運行到76行,其中間變量actual的值是“I am a? teacher”闯割,而期望的字符串(exceptedString)也是“I am a teacher”彻消。
本文來自朱少民老師的《輕輕松松自動化測試》,如有侵權(quán)宙拉,請通知后刪除宾尚。