趙衛(wèi)東 彭偲
摘? 要: 單元測(cè)試是軟件測(cè)試中的最底層的一種測(cè)試活動(dòng),是軟件開發(fā)中不可忽視的一個(gè)環(huán)節(jié),但我國(guó)高校軟件單元測(cè)試的教學(xué)效果并不理想。本文分析了傳統(tǒng)實(shí)驗(yàn)教學(xué)存在的問題,引入先進(jìn)流行的開源測(cè)試框架,設(shè)計(jì)了單元測(cè)試實(shí)驗(yàn)課程教學(xué)內(nèi)容;采用任務(wù)驅(qū)動(dòng)教學(xué)方法,以理論知識(shí)為基礎(chǔ),以企業(yè)需求為標(biāo)桿,對(duì)實(shí)驗(yàn)教學(xué)方法進(jìn)行了改革,收到了良好的教學(xué)效果。
關(guān)鍵詞: 單元測(cè)試教學(xué);軟件開發(fā);實(shí)驗(yàn)課程;JUnit
中圖分類號(hào): TP311.56; G712? ? 文獻(xiàn)標(biāo)識(shí)碼: A? ? DOI:10.3969/j.issn.1003-6970.2019.07.042
【Abstract】: Unit testing is the lowest level of testing activities in software testing. It is a link that cannot be ignored? in software development. However, the teaching effect of software unit testing in Chinese universities is not ideal. This paper analyzes the problems existing in traditional experimental teaching, introduces the advanced and popular open source testing framework, and designs the teaching content of the unit test experiment course. It adopts the task-driven teaching method, based on the theoretical knowledge, and takes the enterprise demand as the benchmark to carry out the experimental teaching method. The reform received good teaching results.
【Key words】: Unit test teaching; Software development; Experimental lesson; JUnit
0? 引言
近年來,隨著計(jì)算機(jī)軟件走進(jìn)社會(huì)的各個(gè)領(lǐng)域,軟件測(cè)試的重要性也在不斷提高。企業(yè)更加重視并且愿意投入更多時(shí)間和人力成本在軟件測(cè)試上[1],因此許多高校也將軟件測(cè)試設(shè)為獨(dú)立課程,力求為國(guó)家和企業(yè)培養(yǎng)出更多測(cè)試領(lǐng)域的人才。
然而,單元測(cè)試的教學(xué)效果仍然不盡人意,原因主要有兩方面:一方面,單元測(cè)試不僅需要專業(yè)測(cè)試人員,還需要開發(fā)者的積極配合和參與。如今部分開發(fā)工程師、項(xiàng)目經(jīng)理仍然懷著傳統(tǒng)的觀念,認(rèn)為軟件測(cè)試是測(cè)試工程師的工作,開發(fā)工程師不需要參與,甚至認(rèn)為讓開發(fā)工程師參與就是“浪費(fèi)時(shí)間”,會(huì)影響項(xiàng)目的開發(fā)進(jìn)度[1]。這種觀念影響了高校學(xué)生,部分學(xué)生誤認(rèn)為開發(fā)工程師無需學(xué)習(xí)測(cè)試相關(guān)知識(shí)。學(xué)生對(duì)測(cè)試課程的不重視,使得教學(xué)工作開展并不順利。
另一方面,部分高校的單元測(cè)試教學(xué)課程設(shè)計(jì)也不盡合理[3]。主要存在兩個(gè)問題:一是課程的內(nèi)容相對(duì)陳舊,與軟件行業(yè)發(fā)展的進(jìn)度嚴(yán)重脫節(jié)。部分高校使用的教材或者案例都來自多年前的資料,其技術(shù)已經(jīng)過時(shí)或者不適合現(xiàn)在的軟件開發(fā)。二是缺乏實(shí)驗(yàn)課程,學(xué)生在課上學(xué)到的理論知識(shí)無法通過實(shí)踐來鞏固,不僅容易遺忘,而且在日后的工作中也無法得到運(yùn)用。
為了提高單元測(cè)試的教學(xué)效果,本文針對(duì)這兩個(gè)方面,設(shè)計(jì)了一種基于開源測(cè)試框架的,任務(wù)驅(qū)動(dòng)式單元測(cè)試實(shí)驗(yàn)課程教學(xué)方法,使學(xué)生可以更高效的學(xué)習(xí)單元測(cè)試,并有能力將其運(yùn)用于實(shí)際工作或項(xiàng)目中。
1? 單元測(cè)試框架的選擇
1.1? 當(dāng)今流行的單元測(cè)試工具
由于單元測(cè)試中測(cè)試的對(duì)象為具體代碼段,所以絕大多數(shù)的單元測(cè)試框架都只能服務(wù)于一種特定的開發(fā)語言?,F(xiàn)在較為流行的幾種開發(fā)語言為Java語言、C系列語言、Python語言以及JavaScript語言,每種語言都有得到業(yè)內(nèi)認(rèn)可的單元測(cè)試框架。例如,Java語言的JUnit框架,C++語言的GoogleTest框架以及Python語言的unittest框架都是非常優(yōu)秀的單元測(cè)試框架。
1.2? JUnit測(cè)試框架的優(yōu)勢(shì)
本課程綜合分析了多種開發(fā)語言和測(cè)試框架,最終選擇Java語言的JUnit作為教學(xué)框架,其原因如下:
(1)Java仍然是使用最廣泛的語言。近年來隨著智能手機(jī)的發(fā)展,許多企業(yè)都在開發(fā)手機(jī)App來為用戶提供更便捷的服務(wù),而Android系統(tǒng)作為市場(chǎng)份額占有率最高的系統(tǒng),其主要開發(fā)語言就是Java。此外,Java是最常用的服務(wù)端開發(fā)語言,目前大多數(shù)系統(tǒng)的服務(wù)端使用Java開發(fā)。
(2)JUnit本身功能十分強(qiáng)大,是Java語言中最受歡迎的單元測(cè)試框架[2]。傳統(tǒng)的單元測(cè)試方法是在程序中內(nèi)嵌代碼輸出數(shù)據(jù),然后再由人工查看來判斷程序是否存在問題。這種方式不僅繁瑣、代碼侵入性高,也可能出現(xiàn)失誤。引入了JUnit框架后,利用其斷言功能編寫相應(yīng)的測(cè)試代碼,可以解決上述問題,并且方便進(jìn)行回歸測(cè)試。JUnit提供了擴(kuò)展功能,能讓用戶自定義斷言的方法或者Runner來進(jìn)行個(gè)性化測(cè)試[5]。測(cè)試完成后,JUnit能幫助用戶分析失敗原因和定位問題所在。
(3)JUnit擁有良好的生態(tài)圈[6]。由于JUnit在Java項(xiàng)目和Android App項(xiàng)目中被廣泛使用[7],主流的集成開發(fā)環(huán)境(例如Eclipse、IDEA和Android Studio)都為JUnit提供了官方插件,用戶在這些開發(fā)環(huán)境中使用起來極為方便。例如,可以一鍵生成對(duì)應(yīng)的測(cè)試報(bào)告,或是一鍵重新測(cè)試上一次未通過部分等等。此外,部分常用的Java第三方框架(例如Spring)也為JUnit提供了原生支持。
2? 實(shí)驗(yàn)內(nèi)容設(shè)計(jì)
2.1? 實(shí)驗(yàn)?zāi)康?/p>
實(shí)驗(yàn)的目的包括以下幾點(diǎn):
(1)掌握在IntelliJ IDEA開發(fā)環(huán)境中引入開源框架JUnit的方法。
(2)掌握使用JUnit進(jìn)行單元測(cè)試的基本步驟與操作方法。
(3)掌握J(rèn)Unit的注解功能。
(4)掌握使用JUnit進(jìn)行參數(shù)化測(cè)試的方法。
2.2? 實(shí)驗(yàn)內(nèi)容
實(shí)驗(yàn)的內(nèi)容主要包括:
(1)使用IntelliJ IDEA創(chuàng)建項(xiàng)目,編寫業(yè)務(wù)邏輯代碼作為受測(cè)程序。
(2)在IntelliJ IDEA中引入JUnit框架,針對(duì)業(yè)務(wù)代碼編寫對(duì)應(yīng)的測(cè)試代碼。
(3)執(zhí)行測(cè)試操作和觀察測(cè)試結(jié)果。
(4)編寫多個(gè)測(cè)試方法,利用集成開發(fā)環(huán)境提供的功能進(jìn)行批量測(cè)試和回歸測(cè)試。
(5)理解JUnit的注解功能。
(6)結(jié)合理論知識(shí),為一個(gè)特定功能單元設(shè)計(jì)一套完整的測(cè)試用例,并學(xué)習(xí)參數(shù)化測(cè)試,以便同時(shí)測(cè)試多個(gè)測(cè)試用例。
(7)學(xué)習(xí)打包測(cè)試功能,同時(shí)測(cè)試多個(gè)測(cè)試類。
2.3? 實(shí)驗(yàn)教學(xué)思路
本實(shí)驗(yàn)課程共包含4個(gè)學(xué)時(shí),分2次授課。授課時(shí)不采取傳統(tǒng)的先講后練的模式,而是采用更高效的任務(wù)驅(qū)動(dòng)課程的形式[8],將講解和練習(xí)結(jié)合在一起。每堂課由數(shù)個(gè)任務(wù)組成,每次講解并演示完一個(gè)任務(wù)后,提供足夠的練習(xí)時(shí)間供學(xué)生實(shí)踐,學(xué)生在明確任務(wù)以后,就開始進(jìn)行準(zhǔn)備工作[9]。
下文將介紹每個(gè)任務(wù)的實(shí)驗(yàn)步驟[10]。
2.3.1? 任務(wù)一:編寫受測(cè)程序代碼
(1)啟動(dòng)IDEA,新建一個(gè)Java項(xiàng)目。
(2)在項(xiàng)目的src文件夾下新建一個(gè)計(jì)算器類Calculator,作為受測(cè)程序。
(3)在Calculator類下添加add、subtract等方法并編寫相應(yīng)代碼用于測(cè)試,如圖1所示。
2.3.2? 任務(wù)二:引入JUnit并編寫測(cè)試代碼
(1)在項(xiàng)目的根目錄下建立一個(gè)test文件夾,然后將此文件夾設(shè)定為測(cè)試源代碼目錄。
(2)在Calculator類名上右擊并依次點(diǎn)擊“Go To”和“Test”,在彈出的浮窗中選擇“Create New Test”選項(xiàng)。
(3)在彈出的對(duì)話框中,點(diǎn)擊Fix來添加IDEA內(nèi)置的JUnit依賴到項(xiàng)目中,在Testing Library中選擇JUnit 4,填寫類名CalculatorTest,全選要測(cè)試的方法并點(diǎn)擊確認(rèn),如圖2所示。
(4)在JUnit生成的模板代碼的基礎(chǔ)上,利用斷言編寫測(cè)試代碼,如圖3所示。
2.3.3? 任務(wù)三:執(zhí)行單個(gè)方法測(cè)試和批量方法測(cè)試
(1)點(diǎn)擊方法名左側(cè)的綠色三角形按鈕來進(jìn)行單個(gè)方法的測(cè)試。
(2)點(diǎn)擊類名左側(cè)的雙綠色三角形按鈕來進(jìn)行整個(gè)類的批量測(cè)試。
(3)觀察測(cè)試結(jié)果,對(duì)于未通過的測(cè)試,根據(jù)JUnit給出的提示來糾正原程序代碼,然后通過“執(zhí)行上一次未通過的測(cè)試”功能校驗(yàn)效果。
2.3.4? 任務(wù)四:利用注解優(yōu)化代碼
(1)在CalculatorTest類新建一個(gè)Calculator類的成員變量,并新建一個(gè)init方法,在init方法中將其實(shí)例化。
(2)在init方法上方添加注解@Before。
(3)去掉測(cè)試方法中實(shí)例化Calculator的代碼,使用成員變量的實(shí)例代替,如圖4所示。
(4)運(yùn)行檢驗(yàn)是否可以通過,并思考@Before注解的作用。
(5)分別使用@After、@BeforeClass、@AfterClass注解來了解其作用,思考他們的觸發(fā)時(shí)機(jī)、順序和實(shí)際用途。
2.3.5? 任務(wù)五:使用參數(shù)化測(cè)試來測(cè)試多個(gè)用例
(1)新建一個(gè)ParamAddTest類,并添加@RunWith (Parameterized.class)注解。
(2)在ParamAddTest類下新建三個(gè)成員變量input1、input2、output,在構(gòu)造函數(shù)中將其初始化。
(3)按同樣的思路編寫測(cè)試代碼,與普通測(cè)試不同的是,要將其中的參數(shù)對(duì)應(yīng)替換成input1、input2和output。
(4)新建一個(gè)data方法用來提供參數(shù),并在此方法加上@Parameters注解,如圖5所示。
(5)執(zhí)行測(cè)試,若測(cè)試未通過,JUnit會(huì)指出導(dǎo)致未通過的測(cè)試用例以助于分析原因。
2.3.6? 任務(wù)六:使用打包測(cè)試進(jìn)行批量類測(cè)試
(1)新建一個(gè)SuiteTest類。
(2)在SuiteTest類的類名上方添加@RunWith (Suite.class)注解。
(3)在SuiteTest類的類名上方添加@Suite. SuiteClasses({***})注解,其中***部分填寫要打包測(cè)試的類名,例如@Suite.SuiteClasses({Param AddTest.class, CalculatorTest.class}),如圖6所示。
(4)執(zhí)行測(cè)試,若測(cè)試未通過,JUnit會(huì)指出未通過的測(cè)試類以及錯(cuò)誤信息。
3? 實(shí)驗(yàn)教學(xué)方法
3.1? 傳統(tǒng)的教學(xué)方法的弊端
相比較其他測(cè)試活動(dòng)而言,單元測(cè)試需要開發(fā)工程師的參與,甚至是以開發(fā)工程師為主體的。大多數(shù)企業(yè)都比較重視單元測(cè)試,部分企業(yè)甚至對(duì)于單元測(cè)試有強(qiáng)制性要求[11]。傳統(tǒng)的課程沒有強(qiáng)調(diào)這一點(diǎn),使用的技術(shù)與教材也相對(duì)陳舊,這容易讓學(xué)生產(chǎn)生“單元測(cè)試已經(jīng)過時(shí)”或者“開發(fā)者對(duì)于測(cè)試課程只需了解”的誤解,讓學(xué)生對(duì)課程的積極性較低。
正因?yàn)閱卧獪y(cè)試是由開發(fā)工程師為主的,所以它更強(qiáng)調(diào)實(shí)踐和編碼[12]。傳統(tǒng)的教學(xué)方法講述理論知識(shí)占用時(shí)間比例較大,分配的實(shí)驗(yàn)課程時(shí)間則較少甚至根本沒有。教學(xué)內(nèi)容枯燥,學(xué)生積極性不高[13]。這導(dǎo)致了理論與實(shí)踐相分離,學(xué)生無法將學(xué)到理論知識(shí)進(jìn)行實(shí)際運(yùn)用,在課后也沒有進(jìn)一步學(xué)習(xí)的方向,學(xué)習(xí)效率很低[14]。
3.2? 改進(jìn)的教學(xué)方法總結(jié)
改進(jìn)的教學(xué)方法更注重于用實(shí)驗(yàn)來鞏固理論,將二者有機(jī)結(jié)合在一起,做到不僅能讓學(xué)生掌握必備的理論知識(shí),還能用代碼將其體現(xiàn)出來,直接將學(xué)到的知識(shí)運(yùn)用于今后的實(shí)習(xí)項(xiàng)目或工作中。
教學(xué)使用到的前置知識(shí)為較基礎(chǔ)的必修課程,只需掌握J(rèn)ava基礎(chǔ)即能上手,不會(huì)使學(xué)生喪失學(xué)習(xí)積極性。隨后通過循序漸進(jìn)的任務(wù)式教學(xué),逐步加深課程難度,即使基礎(chǔ)薄弱也能跟上節(jié)奏;課后提出思考問題,學(xué)有余力的學(xué)生則能找到課后深入學(xué)習(xí)的思路和方向,有效的提高了教學(xué)效果。
4? 實(shí)驗(yàn)教學(xué)方法展望
改進(jìn)的實(shí)驗(yàn)方法切實(shí)有效的提高了教學(xué)效果,但是仍然有改進(jìn)空間。實(shí)驗(yàn)中使用了Java作為教學(xué)語言,但使用的教學(xué)案例相對(duì)較基礎(chǔ)。調(diào)查發(fā)現(xiàn),在學(xué)習(xí)軟件測(cè)試課程之前,大部分學(xué)生已經(jīng)學(xué)習(xí)過較多的編碼課程,擁有一定的知識(shí)儲(chǔ)備和實(shí)踐能力,可以考慮進(jìn)一步提高課程深度。
考慮到Java的語言目前主要運(yùn)用于Android和Web的項(xiàng)目中[15],二者目前對(duì)JUnit都有相應(yīng)的支持。在后續(xù)的教學(xué)中,可以根據(jù)實(shí)際情況,將JUnit融入Android或Web項(xiàng)目中進(jìn)行教學(xué),提高課程深度的同時(shí),與企業(yè)需求直接接軌,可更好的提升教學(xué)效果。
參考文獻(xiàn)
[1] 徐福禎. 計(jì)算機(jī)軟件測(cè)試方法及應(yīng)用實(shí)踐[J]. 信息與電腦(理論版), 2018(02): 14-16.
[2] 朱冬玲. 基于先進(jìn)工作過程的軟件測(cè)試課程教學(xué)[J]. 電腦與電信, 2013(11): 33-34.
[3] 陳站華. 軟件單元測(cè)試[J].無線電通信技術(shù), 2003(05): 50-51.
[4] Vahid Garousi Yusifo?lu, Yasaman Amannejad, Aysu Betin Can. Software test-code engineering: A systematic mapping [J]. Information and Software Technology, 2015, 58.
[5] 白凱, 崔冬華. 基于JUnit自動(dòng)化單元測(cè)試的研究[J]. 計(jì)算
機(jī)與數(shù)字工程, 2010, 38(02): 52-54+103.
[6] Mourad Badri, Fadel Toure,Luc Lamontagne. Predicting Unit Testing Effort Levels of Classes: An Exploratory Study based on Multinomial Logistic Regression Modeling[J]. Procedia Computer Science, 2015, 62.
[7] 劉升貴. 基于MVP模式的Android應(yīng)用程序?qū)崿F(xiàn)及其單元測(cè)試研究[J]. 福建電腦, 2017, 33(07): 94-95.
[8] 王艷輝. 基于任務(wù)驅(qū)動(dòng)的軟件測(cè)試課程教學(xué)模式研究與應(yīng)用[J]. 濟(jì)南職業(yè)學(xué)院學(xué)報(bào), 2017(03): 57-58+67.
[9] 周洪茜, 劉丹. 基于思維導(dǎo)圖的翻轉(zhuǎn)課堂教學(xué)模式研究[J]. 軟件, 2018, 39(4): 63-67.
[10] 王芳, 鄧一星, 秦映波. 敏捷軟件項(xiàng)目管理課程教學(xué)方案研究與實(shí)踐[J]. 軟件, 2018, 39(4): 77-81.
[11] 董威. 單元測(cè)試及測(cè)試工具的研究與應(yīng)用[J]. 微型電腦應(yīng)用, 2008(05): 24-26+23+5.
[12] 蔡高亮. 軟件單元測(cè)試[J]. 信息技術(shù)與標(biāo)準(zhǔn)化, 2008(Z1): 41-43.
[13] 閆實(shí), 劉占波, 王曉麗. 云計(jì)算技術(shù)在高校計(jì)算機(jī)基礎(chǔ)教學(xué)中的應(yīng)用[J]. 軟件, 2018, 39(6): 167-169.
[14] 鞠小林, 陳翔, 文萬志, 張艷梅. “產(chǎn)教研”融合的軟件測(cè)試課程案例庫(kù)構(gòu)建[J]. 計(jì)算機(jī)教育, 2019(03): 121-125.
[15] 馬金鳴. 計(jì)算機(jī)軟件開發(fā)中JAVA編程語言的應(yīng)用[J]. 電子技術(shù)與軟件工程, 2017(17): 53.