三、軟件測試
在軟件開發(fā)的一列活動中,為了**軟件的可靠性,人們研究并使用了很多方法進行分析、設(shè)計及編碼實現(xiàn)。但是由于軟件產(chǎn)品本身無形態(tài),它是復(fù)雜的、知識高度密集的邏輯產(chǎn)品,其中不可能沒有錯誤。物理產(chǎn)品在出廠前都要進行嚴格的檢驗,軟件產(chǎn)品也不例外。軟件開發(fā)總伴隨著軟件質(zhì)量**的活動,而軟件測試是主要活動之一。軟件測試代表了需求分析、設(shè)計、編碼的最終復(fù)審。測試是一項很艱苦的工作,其工作量約占軟件開發(fā)總工作量的40%以上,特別對一些關(guān)系到人的生命安全的軟件,共測試成本可能相當(dāng)于開發(fā)階段總成本的3~5倍。
(一) 測試的基本概念
1.測試的目的
軟件測試的目的是盡可能多地發(fā)現(xiàn)軟件產(chǎn)品(主要是指程序)中的錯誤和缺陷。明確測試的目的是一件非常重要的事,因為在現(xiàn)實世界中對測試工作存在著許多模糊或者錯誤的看法,這些看法嚴重影響著測試工作的順利進行。有人認為測試是為了證明程序是正確的,也就是說程序不再有錯誤,事實證明這是不現(xiàn)實的。因為要**測試來發(fā)現(xiàn)程序中的所有錯誤就要窮舉所有可能的輸入數(shù)據(jù),檢查它們是否產(chǎn)生正確的結(jié)果。例如,一個需要3個16位字長的整型輸入數(shù)據(jù)的程序,輸入數(shù)據(jù)的所有組合情況大約有3×10 14 種,若每組數(shù)據(jù)的測試時間為1ms,那么即使一年365天,每天24小時地測試,也大約需要1萬年的時間。
2.測試用例
要進行測試,除了要有測試數(shù)據(jù)(或稱輸入數(shù)據(jù))外,還應(yīng)同時給出該組測試數(shù)據(jù)應(yīng)該得以怎樣的輸出結(jié)果,我們稱它為預(yù)期結(jié)果。在測試時將實際的輸出結(jié)果與預(yù)期結(jié)果比較,若不同則表示發(fā)現(xiàn)了錯誤,因此測試用例是由測試數(shù)據(jù)和預(yù)期結(jié)果構(gòu)成的。為了發(fā)現(xiàn)程序中的錯誤,應(yīng)竭力設(shè)計能暴露錯誤的測試用例。一個好的測試用例是極有可能發(fā)現(xiàn)迄今為止尚未發(fā)現(xiàn)的錯誤的測試用例。一次成功的測試是發(fā)現(xiàn)了至今為止尚未發(fā)現(xiàn)的錯誤的測試。
3.測試的原則
基于上述測試目的,我們可以考慮以下有關(guān)測試的原則:
(1)確定預(yù)期輸出結(jié)果是測試用例必不可少的一部分。如果只有測試數(shù)據(jù)而無預(yù)期結(jié)果,那么就不易判斷測試結(jié)果是否正確。
(2)程序員應(yīng)避免測試自己的程序,程序設(shè)計機構(gòu)不應(yīng)測試自己的程序。這是因為程序中的錯誤往往是由于程序員對問題說明的誤解,由他來測試自己的程序就不易找出因這種誤解而產(chǎn)生的錯誤。此外,開發(fā)程序是一項建設(shè)性的工作,而測試則是一項破壞性的工作(證明程序有錯),這對開發(fā)人員或機構(gòu)來說在心理上是難以容忍的。為了證明自己的程序沒有錯誤或錯誤很少,他們往往不去選擇容易發(fā)現(xiàn)錯誤的測試用例,而選擇容易**的測試用例。當(dāng)然,這并不意味著程序員都不能測試自己的程序,如單元測試通常就是由程序員自己測試的。
(3)徹底檢查每個測試結(jié)果。如果不仔細檢查測試結(jié)果,有些已經(jīng)測試出來的錯誤也可能被遺漏掉。
(4)對非法的非預(yù)期的輸入數(shù)據(jù)也要像合法的和預(yù)期的輸入數(shù)據(jù)一樣編寫測試用例。
(5)檢查程序是否做了應(yīng)做的事是成功的一半,另一半是看程序是否做了不該做的事。
(6)除了真正沒有用的程序外,一定不要扔掉測試用例。因為在改正錯誤或程序維護后還要進行重新測試。
(7)在規(guī)劃測試時不要設(shè)想程序中不會查出錯誤。
(8)程序模塊經(jīng)測試后,殘存的錯誤數(shù)目往往與已發(fā)現(xiàn)的錯誤數(shù)目成比例。實踐證明,程序中的大量錯誤僅與少量的程序模塊有關(guān),因此當(dāng)A模塊找出的錯誤比B模塊多得多時,很可能A模塊殘存的錯誤仍比B模塊殘存的錯誤多多。
4.白盒測試和黑盒測試
測試的關(guān)鍵是測試用例的設(shè)計,其方法可分成兩類:白盒測試和黑盒測試。白盒測試是把程序看成裝在一只透明的白盒子里,測試者完全了解程序結(jié)構(gòu)和處理過程。它根據(jù)程序的內(nèi)部邏輯來設(shè)計測試用例,檢查程序中的邏輯通路是否都按預(yù)定的要求正確地工作。黑盒測試是把程序看成一只黑盒子,測試者完全不了解(或不考慮)程序的結(jié)構(gòu)和處理過程。它根據(jù)規(guī)格說明書規(guī)定的功能來設(shè)計測試用例,檢查程序的功能是否符合規(guī)格說明的要求。
(二) 測試步驟
軟件測試的主要步驟有單元測試,集成測試和確認測試。
1.單元測試(unit testing)
單元測試也稱模塊測試。通常單元測試可放在編碼階段,程序員在編寫好一個模塊后,總會(也應(yīng)該)對自己編寫的模塊進行測試,檢查它是否實現(xiàn)了詳細設(shè)計說明書中規(guī)定的模塊功能 和算法。單元測試主要發(fā)現(xiàn)編碼和詳細設(shè)計中產(chǎn)生的錯誤,通常采用白盒測試。測試一個模塊時需要編寫一個驅(qū)動模塊和若干個樁(stub)模塊,如下圖所示。驅(qū)動模塊的功能是向被測試模塊提供測試數(shù)據(jù),驅(qū)動(即調(diào)用)被測模塊,并從被測模塊中接受測試結(jié)果。樁模塊的功能是模擬被模塊所調(diào)用的子模塊,它接受被測模塊的調(diào)用,檢驗調(diào)用參數(shù),模擬被調(diào)用的子模塊功能,把結(jié)果送回給被測模塊。在模塊結(jié)構(gòu)圖中,頂層模塊測試時不需要驅(qū)動模塊,最底層的模塊測試時不需要樁模塊。
2.集成測試(integration testing)
集成測試也稱組裝測試,它是對由各模塊組裝而成的程序進行測試,主要檢查模塊間的接口和通信。集成測試主要發(fā)現(xiàn)設(shè)計階段產(chǎn)生的錯誤,通常采用黑盒測試。集成的方式可分成非漸增式集成和漸增式集成。非漸增式集成是先測試所有的模塊,然后把這些模塊集成在一起對整個程序進行測試。漸增式集成是將單元測試和集成測試合并在一起,它根據(jù)模塊結(jié)構(gòu)圖,按某種次序選一個尚未測試的模塊,把它同已經(jīng)測試好的模塊組合在一起對整個程序進行測試,每次增加一個模塊,直至所有模塊全部集成在程序中。漸增式集成又可分成自頂向下集成和自底向上集成。自頂向下集成先測試上層模塊,再測試下層模塊。由于測試下層模塊時它的上層模塊已測試過,所以可以用其上層模塊作為它的驅(qū)動模塊,而不必另編驅(qū)動模塊。自底向上集成先測試下層模塊,再測試上層模塊。同樣道理,在自底向上集成時可用下層模塊作為上層模塊的樁模塊,而不必另外編寫樁模塊。
3.確認測試(walidation testing)
確認測試的任務(wù)是檢查軟件的功能、性能及其他特征是否與用戶的需求一致,它是以需求規(guī)格說明書(即需求規(guī)約)作為依據(jù)的測試。確認測試通常采用黑盒測試。確認測試首先測試程序是否滿足需求規(guī)格說明書所列的各項要求,然后要進行軟件配置復(fù)查,特別是文檔是否齊全,各方面的質(zhì)量是否符合要求等。如果一個軟件是為某個客戶定制的,那么最后由客戶來實施驗收測試(acceptance testing),以便客戶確認該軟件是否他所需要的。如果一個軟件是作為產(chǎn)品被許多客戶使用的話,那不可能為每個客戶進行驗收測試。大多數(shù)軟件生產(chǎn)者使用一種Alpha測試和Beta測試的過程,來揭露僅由最終用戶才能發(fā)現(xiàn)的錯誤。Alpha測試是在開發(fā)者的現(xiàn)場由客戶來實施的,被測試的軟件是在開發(fā)者從用戶的角度進行常規(guī)設(shè)置的環(huán)境下運行的。Beat測試是在一個或多個客戶的現(xiàn)場由該軟件的最終用戶實施的。與Alpha測試不同的是,Beat測試時開發(fā)者通常是不在場的。Alpha測試和Beat測試除了進一步發(fā)現(xiàn)程序中的錯誤外,還能發(fā)現(xiàn)使用上的問題。經(jīng)過確認測試后的軟件通常就可交付使用了。
(三) 白盒測試的測試用例設(shè)計
白盒測試是根據(jù)程序的內(nèi)部邏輯來設(shè)計測試用例,常用的技術(shù)是邏輯覆蓋,即考察用測試數(shù)據(jù)運行被測程序時對程序邏輯的覆蓋程度。主要的覆蓋標準有6種:語句覆蓋、判定覆蓋、條件覆蓋、判定/條件覆蓋、條件組合覆蓋、路徑覆蓋。為了提高測試的效率,應(yīng)選擇最少的測試用例來滿足指定的覆蓋標準。
1.語句覆蓋
語句覆蓋是指選擇足夠的測試用例,使得運行這些測試用例時,被測程序的每個語句至少執(zhí)行一次。
2.判定覆蓋
判定覆蓋又稱為分支覆蓋。它是指選擇足夠的測試用例,使得運行這些測試用例時,每個判定的所有可能結(jié)果至少出現(xiàn)一次(即判定的每個分支至少經(jīng)過一次)。
3.條件覆蓋
在軟件設(shè)計過程中,一個判定往往由多個條件組成,判定覆蓋僅考慮了判定的結(jié)果而沒有考慮每個條件的可能結(jié)果。條件覆蓋是指選擇足夠的測試用例,使得運行這些測試用例時,判定中的每個條件的所有可能結(jié)果至少出現(xiàn)一次。
4.判定/條件覆蓋
判定/條件覆蓋是指選擇足夠的測試用例。使得運行這些測試用例時,判定中每個條件的所有可能結(jié)果至少出現(xiàn)一次,并且每個判定本身的所有可能結(jié)果至少出現(xiàn)一次。顯然,滿足判定/條件覆蓋標準的測試用例一定也滿足判定覆蓋、條件覆蓋和語句覆蓋標準。在某些程序的測試中,如果選擇得好,判定覆蓋、條件覆蓋和判定/條件覆蓋可以使用相同的最少的測試用例。
5.條件組合覆蓋
在條件覆蓋中考慮了判定中每個條件的所有可能結(jié)果,但并未考慮條件的組合情況。條件組合覆蓋是指選擇足夠的測試用例,使得運行這些測試用例時,每個判定中條件結(jié)果的所有可能組合至少出現(xiàn)一次。由于條件組合覆蓋使每個判定中條件結(jié)果的所有可能組合都至少出現(xiàn)一次,因此判定本身的所有可能結(jié)果也一定至少出現(xiàn)一次,同時也使每個條件的所有可能結(jié)果至少出現(xiàn)一次。因此,條件組合覆蓋是上述5種覆蓋標準中的一種。然而,條件組合覆蓋還不能**程序中所有可能的路徑都被覆蓋。
6.路徑覆蓋
路徑覆蓋是指選擇足夠的測試用例,使得運行這些測試用例時,程序的每條可能執(zhí)行到的路徑都至少經(jīng)過一次(如果程序中有環(huán)路,則要求每條環(huán)路至少經(jīng)過一次)。路徑覆蓋實際上是考慮了程序中各種判定結(jié)果的所有可能組合,但它并未考慮判定中的條件結(jié)果的組合,因此它是一種比較強的覆蓋標準,但并不能代替條件覆蓋和條件組合覆蓋。
黑盒測試是根據(jù)規(guī)格說明所規(guī)定的功能來設(shè)計測試用例,它不考慮程序中的內(nèi)部結(jié)構(gòu)和處理過程。常用的黑盒測試技術(shù)有等價類劃分、邊值分析、錯誤猜測等。
1.等價類劃分
前面已經(jīng)講過,不能窮舉所有可能的輸入數(shù)據(jù)來進行測試,所以只能選取少量有代表性的輸入數(shù)據(jù),來揭露盡可能多的程序錯誤。這里首先要介紹一個有效的輸入數(shù)據(jù)和無效的輸入數(shù)據(jù)。有效的輸入數(shù)據(jù)是指符合規(guī)格說明要求的合理的輸入數(shù)據(jù),它主要用來檢驗程序是否實現(xiàn)了規(guī)格說明中的功能。無效的輸入數(shù)據(jù)是指不符合規(guī)格說明要求的不合理或非法的輸入數(shù)據(jù),它主要用來檢驗程序是否做了規(guī)格說明以外的事。如果把所有可能的輸入數(shù)據(jù)(有效的和無效的)劃分成若干個等價類,那么可以合理地做出假定:如果等價類中的一個輸入數(shù)據(jù)能檢測出一個錯誤,那么等價類中的其他輸入數(shù)據(jù)也能檢測出同一個錯誤;反之,如果一個輸入數(shù)據(jù)不能檢測出某個錯誤,那么等價類中其他輸入數(shù)據(jù)也不能發(fā)現(xiàn)這一錯誤(除非這個等價類的某個子集還屬于另一等價類)。等價類劃分方法首先把輸入數(shù)據(jù)劃分成若干個有效等價類和若干個無效等價類,然后設(shè)計測試用例覆蓋這些等價類。來源:www.examda.com
2.邊值分析
大量的實踐說明,程序中在處理邊界情況時出錯的概率比較大,因此設(shè)計一些測試用例,使程序運行在邊界情況附近,這樣揭露程序中錯誤的可能性就更大。所謂邊界條件是指相對于輸入與輸出等價類直接在其邊界上,或稍高于其邊界,或稍低于其邊界的這些狀態(tài)條件。使用等價類劃分方法設(shè)計測試用例時,原則上講,等價類中的任一輸入數(shù)據(jù)都可作為該等價類的代表用作測試用例。而邊值分析則是專門挑選那些位于邊界附近的值作為測試用例。由于邊值分析方法所設(shè)計的測試用例,更有可能發(fā)現(xiàn)程序中的錯誤,因此經(jīng)常把邊值分析方法與其他設(shè)計測試用例方法結(jié)合起來使用。
3.錯誤猜測
錯誤猜測是一種憑直覺和經(jīng)驗推測某些可能存在的錯誤,從而針對這些可能存在的錯誤設(shè)計測試用例的方法。這種方法沒有機械的執(zhí)行步驟,主要依靠直覺和經(jīng)驗。

