單元測(cè)試實(shí)施解惑(一)
在剛過(guò)去的一個(gè)月中,我完成了一個(gè)小軟件框架的設(shè)計(jì)與實(shí)現(xiàn)。期間由于并行開(kāi)發(fā)的需要,在沒(méi)有對(duì)代碼完成單元測(cè)試的情形下我將之check in到了SVN的主干上,隨后的心情很是忐忑。因?yàn)槲抑牢乙欢〞?huì)犯錯(cuò)(事實(shí)也證明在單元測(cè)試完成之前就發(fā)現(xiàn)了兩個(gè)缺陷),害怕給他人帶來(lái)麻煩并影響自己的形象。
另外,由于對(duì)剛加入項(xiàng)目的單元測(cè)試環(huán)境完全不了解,所以在該框架的前期開(kāi)發(fā)工作中我并沒(méi)有運(yùn)用單元測(cè)試漸進(jìn)地保證軟件質(zhì)量。其結(jié)果可想而知,我花了不少時(shí)間去修復(fù)編碼過(guò)程中遺留下來(lái)的低級(jí)錯(cuò)誤。需要指出的是,所在項(xiàng)目是一個(gè)大型嵌入式系統(tǒng),項(xiàng)目編譯一次就得20分鐘左右,調(diào)試效率可以想象。與之不同的是,單元測(cè)試可以在Linux/Cygwin這樣的環(huán)境中完成,加上可以使用gdb進(jìn)行調(diào)試,開(kāi)發(fā)效率提高一個(gè)數(shù)量級(jí)應(yīng)不是問(wèn)題。
由于我深刻地體會(huì)到了單元測(cè)試對(duì)工作與生活質(zhì)量的重要性,所以持“真正高質(zhì)高效的軟件開(kāi)發(fā)工程師,一定是那些深刻理解并切實(shí)實(shí)施單元測(cè)試的人”這一觀點(diǎn)。然而,就我過(guò)去幾年的工作見(jiàn)聞來(lái)看,發(fā)現(xiàn)身邊絕大多數(shù)的工程師并沒(méi)有真正用心去擁抱單元測(cè)試。出現(xiàn)這樣的狀況,我認(rèn)為存在一定的原由,因此想借本文談?wù)勔恍┱J(rèn)識(shí)。
有相當(dāng)一部分工程師是因?yàn)椴⒉涣私馐裁词菃卧獪y(cè)試而沒(méi)能嘗到單元測(cè)試的好處。一部分人認(rèn)為,平時(shí)開(kāi)發(fā)工作中的調(diào)試其實(shí)就是單元測(cè)試(參見(jiàn)《明析單元測(cè)試》),有的則因?yàn)闆](méi)有花時(shí)間學(xué)習(xí)單元測(cè)試而對(duì)之不了解。對(duì)于這些新手,我并不打算在本文對(duì)之“掃盲”,請(qǐng)下載ClearRTOS源碼(點(diǎn)擊下載)和本文的附件自行學(xué)習(xí)。 ClearRTOS 是我為《專業(yè)嵌入式軟件開(kāi)發(fā)》一書(shū)所設(shè)計(jì)的、可在Cygwin和Linux環(huán)境中運(yùn)行的“實(shí)時(shí)”操作系統(tǒng),其中涵蓋有單元測(cè)試方面的內(nèi)容,更具體的信息見(jiàn)文后。
另外的一部分人盡管實(shí)施過(guò)單元測(cè)試,但卻沒(méi)能從中受益,甚至得出“單元測(cè)試無(wú)用”的結(jié)論。這部分人的困惑是我最想在這里加以指出的。歸結(jié)起來(lái),我認(rèn)為實(shí)施過(guò)程中的“縫太大”是其中一大主因。
不少團(tuán)隊(duì)將項(xiàng)目的產(chǎn)品代碼與單元測(cè)試代碼加以區(qū)別對(duì)待,這是產(chǎn)生“縫”的第一大根源。表現(xiàn)之一是,編譯產(chǎn)品代碼與編譯單元測(cè)試代碼采用完全不同的編譯環(huán)境,程序員在日常工作中需要不停地在兩個(gè)編譯環(huán)境中進(jìn)行切換。這種方式很容易讓工程師感到麻煩,甚至因此遭到抵制或棄用。好的方式是,將單元測(cè)試代碼的編譯環(huán)境與產(chǎn)品代碼進(jìn)行無(wú)縫整合。比如,在嵌入式系統(tǒng)項(xiàng)目中做到運(yùn)行“make release”或“make debug”實(shí)現(xiàn)產(chǎn)品代碼編譯,運(yùn)行“make unitest”完成單元測(cè)試代碼編譯(ClearRTOS項(xiàng)目就是這么做的)。做到編譯環(huán)境的無(wú)縫整合需要團(tuán)隊(duì)中存在精通編譯環(huán)境構(gòu)建語(yǔ)言(比如Makefile)的專家。很不幸的是,這方面的專家少得可憐,團(tuán)隊(duì)對(duì)這方面知識(shí)的精進(jìn)也因?yàn)闆](méi)有意識(shí)到其重要性而缺乏動(dòng)力。
表現(xiàn)之二是,產(chǎn)品代碼與單元測(cè)試代碼區(qū)別維護(hù)。采用這種方式的團(tuán)隊(duì),很容易在工作中將單元測(cè)試擺到更低的位置,開(kāi)發(fā)過(guò)程會(huì)先以產(chǎn)品代碼為主,然后(有時(shí)間時(shí))再補(bǔ)上單元測(cè)試代碼。這種方式很容易降低實(shí)施單元測(cè)試的效果,且容易因?yàn)楫a(chǎn)品代碼與單元測(cè)試代碼的不同步而帶來(lái)更大的維護(hù)成本。實(shí)際上,實(shí)施單元測(cè)試的一大好處就是在對(duì)產(chǎn)品代碼進(jìn)行變更時(shí),通過(guò)及時(shí)實(shí)施單元測(cè)試保證軟件質(zhì)量。及時(shí)維護(hù)單元測(cè)試代碼從短期和長(zhǎng)期都具有很好的經(jīng)濟(jì)性,而非象我們想象的那樣成本高昂。
產(chǎn)生“縫”的第二大根源,是因?yàn)楣こ處熢趩卧獪y(cè)試過(guò)程中不能方便地獲得代碼覆蓋報(bào)告。以我的觀點(diǎn),代碼覆蓋報(bào)告應(yīng)在開(kāi)發(fā)環(huán)境中運(yùn)行象“make creport”這樣的命令而輕松獲得(ClearRTOS項(xiàng)目同樣實(shí)現(xiàn)了這一點(diǎn))。我看到過(guò)一些項(xiàng)目,工程師為了獲得覆蓋報(bào)告,需要登錄到一個(gè)Web服務(wù)器上才能查看,而非在工程師的工作機(jī)器上隨手獲取。
產(chǎn)生“縫”的另一大根源與單元測(cè)試的“打樁”方法有關(guān)。被廣為采用的方法是通過(guò)使用象Cmockery這樣的單元測(cè)試框架以打樁的形式,將被測(cè)模塊獨(dú)立出來(lái)。這種方式盡管被廣泛采用,但我覺(jué)得所需付出的成本還是很高的。因?yàn)?#8220;樁的世界”與“產(chǎn)品代碼世界”存在很大的“縫隙”,維護(hù)期間需要不停地在兩個(gè)“世界”進(jìn)行切換,更好的方式是將樁代碼融入到產(chǎn)品代碼中(細(xì)節(jié)我想通過(guò)另一篇文章給出)。
盡管我認(rèn)為單元測(cè)試是一種有效的質(zhì)量保障方法,但其有效性在工程界和學(xué)術(shù)界都存在一定的爭(zhēng)議。
關(guān)于ClearRTOS
ClearRTOS現(xiàn)在是一個(gè)開(kāi)源項(xiàng)目,讀者可以通過(guò)SVN獲取將來(lái)的新版本。為了能在ClearRTOS項(xiàng)目中獲得HTML格式的代碼覆蓋報(bào)告,讀者需在Linux/Cygwin中安裝LCOV(鏈接)。
在ClearRTOS項(xiàng)目中獲取代碼覆蓋報(bào)告的步驟如下:
1)運(yùn)行“tar xzvf ClearRTOS.tar.gz”解壓。
2)運(yùn)行“cd ClearRTOS/build”進(jìn)入編譯目錄。
3)運(yùn)行“make unitest”編譯單元測(cè)試程序。
4)運(yùn)行“make test”執(zhí)行單元測(cè)試程序。
5)運(yùn)行“make creport”獲取單元測(cè)試報(bào)告。報(bào)告可用IE、Chrome等瀏覽器打開(kāi)ClearRTOS/build/coverage/index.html文件進(jìn)行瀏覽。通過(guò)點(diǎn)擊網(wǎng)頁(yè)中的相關(guān)鏈接可以查看到每個(gè)源文件的代碼覆蓋情況。
posted on 2012-09-11 09:58 順其自然EVO 閱讀(230) 評(píng)論(0) 編輯 收藏 所屬分類: 測(cè)試學(xué)習(xí)專欄