2010軟考軟件測(cè)試中面臨的問(wèn)題及解決辦法(1)

字號(hào):

2010軟考軟件測(cè)試中面臨的問(wèn)題及解決辦法(1)

    摘要
    這篇文章主要闡述這樣一個(gè)問(wèn)題:為什么要進(jìn)行煩人的單元測(cè)試?那些剛剛接觸完全測(cè)試概念的開(kāi)發(fā)人員常常遇到這個(gè)問(wèn)題。我們這里將采用“反調(diào)論證”的方法來(lái)回答這個(gè)問(wèn)題, 先提出一些反對(duì)單元測(cè)試的普遍論點(diǎn), 然后我們會(huì)證明這些論點(diǎn)是站不住腳的。那些公開(kāi)發(fā)表的文章和數(shù)據(jù)充分證實(shí)了單元測(cè)試的有效性。
    IPL是一個(gè)獨(dú)立的軟件開(kāi)發(fā)機(jī)構(gòu),成立于1979年,基地設(shè)在Bath。IPL在1988年通過(guò)了ISO9001認(rèn)證,并在1991年通過(guò)TickIT認(rèn)證。IPL開(kāi)發(fā)并提供AdaTEST和Cantata等軟件驗(yàn)證產(chǎn)品。AdaTEST和Cantata的開(kāi)發(fā)遵循了這些標(biāo)準(zhǔn)的要求。
    簡(jiǎn)介
    在使新的產(chǎn)品和業(yè)務(wù)的開(kāi)發(fā)過(guò)程工業(yè)化的嘗試中,軟件的質(zhì)量和可靠性常常被看作是薄弱環(huán)節(jié)。
    在近的十年里,隨著越來(lái)越多的人在開(kāi)發(fā)過(guò)程中采用了設(shè)計(jì)方法論和使用CASE工具,軟件質(zhì)量和可靠性的問(wèn)題越來(lái)越受到重視。大多數(shù)軟件設(shè)計(jì)人員都接受了這方面的培訓(xùn),并且在這些正規(guī)的軟件設(shè)計(jì)方法的使用中取得了很多經(jīng)驗(yàn)。
    但不幸的是,軟件測(cè)試并沒(méi)有得到同樣的重視。很多使用這些軟件設(shè)計(jì)方法的開(kāi)發(fā)活動(dòng)并沒(méi)有使軟件質(zhì)量和可靠性得到控制。修改初的軟件開(kāi)發(fā)活動(dòng)遺留的Bug一般要在軟件維護(hù)費(fèi)用中占到50%的比例,這是不正常的,這些Bug應(yīng)該在有效的軟件測(cè)試過(guò)程中被排除掉。
    這篇文章主要闡述這樣一個(gè)問(wèn)題:為什么要進(jìn)行煩人的單元測(cè)試?那些剛剛接觸完全測(cè)試概念的開(kāi)發(fā)人員常常遇到這個(gè)問(wèn)題。我們這里將采用“反調(diào)論證”的方法來(lái)回答這個(gè)問(wèn)題,先列出一些反對(duì)單元測(cè)試的普遍論點(diǎn),然后我們會(huì)證明這些論點(diǎn)是站不住腳的。那些公開(kāi)發(fā)表的文章和數(shù)據(jù)充分證實(shí)了單元測(cè)試的有效性。
    什么是單元測(cè)試
    單元測(cè)試是在軟件開(kāi)發(fā)過(guò)程中要進(jìn)行的低級(jí)別的測(cè)試活動(dòng),在單元測(cè)試活動(dòng)中,軟件的獨(dú)立單元將在與程序的其他部分相隔離的情況下進(jìn)行測(cè)試。
    在一種傳統(tǒng)的結(jié)構(gòu)化編程語(yǔ)言中,比如C,要進(jìn)行測(cè)試的單元一般是函數(shù)或子過(guò)程。在象C++這樣的面向?qū)ο蟮恼Z(yǔ)言中, 要進(jìn)行測(cè)試的基本單元是類。對(duì)Ada語(yǔ)言來(lái)說(shuō),開(kāi)發(fā)人員可以選擇是在獨(dú)立的過(guò)程和函數(shù),還是在Ada包的級(jí)別上進(jìn)行單元測(cè)試。單元測(cè)試的原則同樣被擴(kuò)展到第四代語(yǔ)言(4GL)的開(kāi)發(fā)中,在這里基本單元被典型地劃分為一個(gè)菜單或顯示界面。
    單元測(cè)試不僅僅是作為無(wú)錯(cuò)編碼一種輔助手段在性的開(kāi)發(fā)過(guò)程中使用,單元測(cè)試必須是可重復(fù)的,無(wú)論是在軟件修改,或是移植到新的運(yùn)行環(huán)境的過(guò)程中。因此,所有的測(cè)試都必須在整個(gè)軟件系統(tǒng)的生命周期中進(jìn)行維護(hù)。
    經(jīng)常與單元測(cè)試聯(lián)系起來(lái)的另外一些開(kāi)發(fā)活動(dòng)包括代碼走讀(Code review),靜態(tài)分析(Static analysis)和動(dòng)態(tài)分析(Dynamic analysis)。靜態(tài)分析就是對(duì)軟件的源代碼進(jìn)行研讀,查找錯(cuò)誤或收集一些度量數(shù)據(jù),并不需要對(duì)代碼進(jìn)行編譯和執(zhí)行。動(dòng)態(tài)分析就是通過(guò)觀察軟件運(yùn)行時(shí)的動(dòng)作,來(lái)提供執(zhí)行跟蹤,時(shí)間分析,以及測(cè)試覆蓋度方面的信息。
    一些流行的誤解
    在明確了什么是單元測(cè)試以后,我們可以進(jìn)行“反調(diào)論證”了。在下面的章節(jié)里,我們列出了一些反對(duì)單元測(cè)試的普遍的論點(diǎn)。然后用充分的理由來(lái)證明這些論點(diǎn)是不足取的。
    它浪費(fèi)了太多的時(shí)間
    一旦編碼完成,開(kāi)發(fā)人員總是會(huì)迫切希望進(jìn)行軟件的集成工作,這樣他們就能夠看到實(shí)際的系統(tǒng)開(kāi)始啟動(dòng)工作了。 這在外表上看來(lái)是一項(xiàng)明顯的進(jìn)步,而象單元測(cè)試這樣的活動(dòng)也許會(huì)被看作是通往這個(gè)階段點(diǎn)的道路上的障礙, 推遲了對(duì)整個(gè)系統(tǒng)進(jìn)行聯(lián)調(diào)這種真正有意思的工作啟動(dòng)的時(shí)間。
    在這種開(kāi)發(fā)步驟中,真實(shí)意義上的進(jìn)步被外表上的進(jìn)步取代了。系統(tǒng)能夠正常工作的可能性是很小的,更多的情況是充滿了各式各樣的Bug。在實(shí)踐中,這樣一種開(kāi)發(fā)步驟常常會(huì)導(dǎo)致這樣的結(jié)果:軟件甚至無(wú)法運(yùn)行。更進(jìn)一步的結(jié)果是大量的時(shí)間將被花費(fèi)在跟蹤那些包含在獨(dú)立單元里的簡(jiǎn)單的Bug上面,在個(gè)別情況下,這些Bug也許是瑣碎和微不足道的,但是總的來(lái)說(shuō),他們會(huì)導(dǎo)致在軟件集成為一個(gè)系統(tǒng)時(shí)增加額外的工期, 而且當(dāng)這個(gè)系統(tǒng)投入使用時(shí)也無(wú)法確保它能夠可靠運(yùn)行。
    在實(shí)踐工作中,進(jìn)行了完整計(jì)劃的單元測(cè)試和編寫(xiě)實(shí)際的代碼所花費(fèi)的精力大致上是相同的。一旦完成了這些單元測(cè)試工作,很多Bug將被糾正,在確信他們手頭擁有穩(wěn)定可靠的部件的情況下,開(kāi)發(fā)人員能夠進(jìn)行更高效的系統(tǒng)集成工作。這才是真實(shí)意義上的進(jìn)步,所以說(shuō)完整計(jì)劃下的單元測(cè)試是對(duì)時(shí)間的更高效的利用。而調(diào)試人員的不受控和散漫的工作方式只會(huì)花費(fèi)更多的時(shí)間而取得很少的好處。
    使用AdaTEST和Cantata這樣的支持工具可以使單元測(cè)試更加簡(jiǎn)單和有效。但這不是必須的,單元測(cè)試即使是在沒(méi)有工具支持的情況下也是一項(xiàng)非常有意義的活動(dòng)。
    它僅僅是證明這些代碼做了什么
    這是那些沒(méi)有首先為每個(gè)單元編寫(xiě)一個(gè)詳細(xì)的規(guī)格說(shuō)明而直接跳到編碼階段的開(kāi)發(fā)人員提出的一條普遍的抱怨, 當(dāng)編碼完成以后并且面臨代碼測(cè)試任務(wù)的時(shí)候,他們就閱讀這些代碼并找出它實(shí)際上做了什么,把他們的測(cè)試工作基于已經(jīng)寫(xiě)好的代碼的基礎(chǔ)上。當(dāng)然,他們無(wú)法證明任何事情。所有的這些測(cè)試工作能夠表明的事情就是編譯器工作正常。是的,他們也許能夠抓住(希望能夠)罕見(jiàn)的編譯器Bug,但是他們能夠做的僅僅是這些。
    如果他們首先寫(xiě)好一個(gè)詳細(xì)的規(guī)格說(shuō)明,測(cè)試能夠以規(guī)格說(shuō)明為基礎(chǔ)。代碼就能夠針對(duì)它的規(guī)格說(shuō)明,而不是針對(duì)自身進(jìn)行測(cè)試。這樣的測(cè)試仍然能夠抓住編譯器的Bug,同時(shí)也能找到更多的編碼錯(cuò)誤,甚至是一些規(guī)格說(shuō)明中的錯(cuò)誤。好的規(guī)格說(shuō)明可以使測(cè)試的質(zhì)量更高,所以后的結(jié)論是高質(zhì)量的測(cè)試需要高質(zhì)量的規(guī)格說(shuō)明。
    在實(shí)踐中會(huì)出現(xiàn)這樣的情況: 一個(gè)開(kāi)發(fā)人員要面對(duì)測(cè)試一個(gè)單元時(shí)只給出單元的代碼而沒(méi)有規(guī)格說(shuō)明這樣吃力不討好的任務(wù)。你怎樣做才會(huì)有更多的收獲,而不僅僅是發(fā)現(xiàn)編譯器的Bug?第一步是理解這個(gè)單元原本要做什么, --- 不是它實(shí)際上做了什么。 比較有效的方法是倒推出一個(gè)概要的規(guī)格說(shuō)明。這個(gè)過(guò)程的主要輸入條件是要閱讀那些程序代碼和注釋, 主要針對(duì)這個(gè)單元, 及調(diào)用它和被它調(diào)用的相關(guān)代碼。畫(huà)出流程圖是非常有幫助的,你可以用手工或使用某種工具。 可以組織對(duì)這個(gè)概要規(guī)格說(shuō)明的走讀(Review),以確保對(duì)這個(gè)單元的說(shuō)明沒(méi)有基本的錯(cuò)誤, 有了這種小程度的代碼深層說(shuō)明,就可以用它來(lái)設(shè)計(jì)單元測(cè)試了。
    我是個(gè)很棒的程序員, 我是不是可以不進(jìn)行單元測(cè)試?
    在每個(gè)開(kāi)發(fā)組織中都至少有一個(gè)這樣的開(kāi)發(fā)人員,他非常擅長(zhǎng)于編程,他們開(kāi)發(fā)的軟件總是在第一時(shí)間就可以正常運(yùn)行,因此不需要進(jìn)行測(cè)試。你是否經(jīng)常聽(tīng)到這樣的借口?
    在真實(shí)世界里,每個(gè)人都會(huì)犯錯(cuò)誤。即使某個(gè)開(kāi)發(fā)人員可以抱著這種態(tài)度在很少的一些簡(jiǎn)單的程序中應(yīng)付過(guò)去。 但真正的軟件系統(tǒng)是非常復(fù)雜的。真正的軟件系統(tǒng)不可以寄希望于沒(méi)有進(jìn)行廣泛的測(cè)試和Bug修改過(guò)程就可以正常工作。
    編碼不是一個(gè)可以性通過(guò)的過(guò)程。在真實(shí)世界中,軟件產(chǎn)品必須進(jìn)行維護(hù)以對(duì)操作需求的改變作出反應(yīng), 并且要對(duì)初的開(kāi)發(fā)工作遺留下來(lái)的Bug進(jìn)行修改。你希望依靠那些原始作者進(jìn)行修改嗎? 這些制造出這些未經(jīng)測(cè)試的原始代碼的資深專家們還會(huì)繼續(xù)在其他地方制造這樣的代碼。在開(kāi)發(fā)人員做出修改后進(jìn)行可重復(fù)的單元測(cè)試可以避免產(chǎn)生那些令人不快的負(fù)作用。
    不管怎樣, 集成測(cè)試將會(huì)抓住所有的Bug
    我們已經(jīng)在前面的討論中從一個(gè)側(cè)面對(duì)這個(gè)問(wèn)題進(jìn)行了部分的闡述。這個(gè)論點(diǎn)不成立的原因在于規(guī)模越大的代碼集成意味著復(fù)雜性就越高。如果軟件的單元沒(méi)有事先進(jìn)行測(cè)試,開(kāi)發(fā)人員很可能會(huì)花費(fèi)大量的時(shí)間僅僅是為了使軟件能夠運(yùn)行,而任何實(shí)際的測(cè)試方案都無(wú)法執(zhí)行。
    一旦軟件可以運(yùn)行了,開(kāi)發(fā)人員又要面對(duì)這樣的問(wèn)題: 在考慮軟件全局復(fù)雜性的前提下對(duì)每個(gè)單元進(jìn)行全面的測(cè)試。 這是一件非常困難的事情,甚至在創(chuàng)造一種單元調(diào)用的測(cè)試條件的時(shí)候,要全面的考慮單元的被調(diào)用時(shí)的各種入口參數(shù)。在軟件集成階段,對(duì)單元功能全面測(cè)試的復(fù)雜程度遠(yuǎn)遠(yuǎn)的超過(guò)獨(dú)立進(jìn)行的單元測(cè)試過(guò)程。
    后的結(jié)果是測(cè)試將無(wú)法達(dá)到它所應(yīng)該有的全面性。一些缺陷將被遺漏,并且很多Bug將被忽略過(guò)去。
    讓我們類比一下,假設(shè)我們要清洗一臺(tái)已經(jīng)完全裝配好的食物加工機(jī)器!無(wú)論你噴了多少水和清潔劑,一些食物的小碎片還是會(huì)粘在機(jī)器的死角位置,只有任其腐爛并等待以后再想辦法。但我們換個(gè)角度想想,如果這臺(tái)機(jī)器是拆開(kāi)的, 這些死角也許就不存在或者更容易接觸到了,并且每一部分都可以毫不費(fèi)力的進(jìn)行清洗。
    它的成本效率不高
    一個(gè)特定的開(kāi)發(fā)組織或軟件應(yīng)用系統(tǒng)的測(cè)試水平取決于對(duì)那些未發(fā)現(xiàn)的Bug的潛在后果的重視程度。這種后果的嚴(yán)重程度可以從一個(gè)Bug引起的小小的不便到發(fā)生多次的死機(jī)的情況。這種后果可能常常會(huì)被軟件的開(kāi)發(fā)人員所忽視(但是用戶可不會(huì)這樣),這種情況會(huì)長(zhǎng)期的損害這些向用戶提交帶有Bug的軟件的開(kāi)發(fā)組織的信譽(yù),并且會(huì)導(dǎo)致對(duì)未來(lái)的市場(chǎng)產(chǎn)生負(fù)面的影響。相反地,一個(gè)可靠的軟件系統(tǒng)的良好的聲譽(yù)將有助于一個(gè)開(kāi)發(fā)組織獲取未來(lái)的市場(chǎng)。
    很多研究成果表明,無(wú)論什么時(shí)候作出修改都要進(jìn)行完整的回歸測(cè)試,在生命周期中盡早地對(duì)軟件產(chǎn)品進(jìn)行測(cè)試將使效率和質(zhì)量得到好的保證。Bug發(fā)現(xiàn)的越晚,修改它所需的費(fèi)用就越高,因此從經(jīng)濟(jì)角度來(lái)看, 應(yīng)該盡可能早的查找和修改Bug。在修改費(fèi)用變的過(guò)高之前,單元測(cè)試是一個(gè)在早期抓住Bug的機(jī)會(huì)。
    相比后階段的測(cè)試,單元測(cè)試的創(chuàng)建更簡(jiǎn)單,維護(hù)更容易,并且可以更方便的進(jìn)行重復(fù)。從全程的費(fèi)用來(lái)考慮, 相比起那些復(fù)雜且曠日持久的集成測(cè)試,或是不穩(wěn)定的軟件系統(tǒng)來(lái)說(shuō),單元測(cè)試所需的費(fèi)用是很低的。
    一些圖表
    這些圖表摘自<<實(shí)用軟件度量>>(Capers Jones,McGraw-Hill 1991),它列出了準(zhǔn)備測(cè)試,執(zhí)行測(cè)試,和修改缺陷所花費(fèi)的時(shí)間(以一個(gè)功能點(diǎn)為基準(zhǔn)),這些數(shù)據(jù)顯示單元測(cè)試的成本效率大約是集成測(cè)試的兩倍 系統(tǒng)測(cè)試的三倍(參見(jiàn)條形圖)。
    (術(shù)語(yǔ)域測(cè)試(Field test)意思是在軟件投入使用以后,針對(duì)某個(gè)領(lǐng)域所作的所有測(cè)試活動(dòng))
    這個(gè)圖表并不表示開(kāi)發(fā)人員不應(yīng)該進(jìn)行后階段的測(cè)試活動(dòng),這次測(cè)試活動(dòng)仍然是必須的。它的真正意思是盡可能早的排除盡可能多的Bug可以減少后階段測(cè)試的費(fèi)用。
    其他的一些圖表顯示高達(dá)50%的維護(hù)工作量被花在那些總是會(huì)有的Bug的修改上面。如果這些Bug在開(kāi)發(fā)階段被排除掉的話,這些工作量就可以節(jié)省下來(lái)。當(dāng)考慮到軟件維護(hù)費(fèi)用可能會(huì)比初的開(kāi)發(fā)費(fèi)用高出數(shù)倍的時(shí)候,這種潛在的對(duì)50%軟件維護(hù)費(fèi)用的節(jié)省將對(duì)整個(gè)軟件生命周期費(fèi)用產(chǎn)生重大的影響。
    結(jié)論
    經(jīng)驗(yàn)表明一個(gè)盡責(zé)的單元測(cè)試方法將會(huì)在軟件開(kāi)發(fā)的某個(gè)階段發(fā)現(xiàn)很多的Bug,并且修改它們的成本也很低。在軟件開(kāi)發(fā)的后期階段,Bug的發(fā)現(xiàn)并修改將會(huì)變得更加困難,并要消耗大量的時(shí)間和開(kāi)發(fā)費(fèi)用。無(wú)論什么時(shí)候作出修改都要進(jìn)行完整的回歸測(cè)試,在生命周期中盡早地對(duì)軟件產(chǎn)品進(jìn)行測(cè)試將使效率和質(zhì)量得到好的保證。 在提供了經(jīng)過(guò)測(cè)試的單元的情況下,系統(tǒng)集成過(guò)程將會(huì)大大地簡(jiǎn)化。開(kāi)發(fā)人員可以將精力集中在單元之間的交互作用和全局的功能實(shí)現(xiàn)上,而不是陷入充滿很多Bug的單元之中不能自拔。
    使測(cè)試工作的效力發(fā)揮到大化的關(guān)鍵在于選擇正確的測(cè)試策略,這其中包含了完全的單元測(cè)試的概念,以及對(duì)測(cè)試過(guò)程的良好的管理,還有適當(dāng)?shù)厥褂孟驛daTEST和Cantata這樣的工具來(lái)支持測(cè)試過(guò)程。這些活動(dòng)可以產(chǎn)生這樣的結(jié)果:在花費(fèi)更低的開(kāi)發(fā)費(fèi)用的情況下得到更穩(wěn)定的軟件。更進(jìn)一步的好處是簡(jiǎn)化了維護(hù)過(guò)程并降低了生命周期的費(fèi)用。有效的單元測(cè)試是推行全局質(zhì)量文化的一部分,而這種質(zhì)量文化將會(huì)為軟件開(kāi)發(fā)者帶來(lái)無(wú)限的商機(jī)。