|
用戶使用低質量的軟件,在運行過程中會產生各種各樣的問題,可能帶來不同程度的嚴重后果,輕者影響系統的正常工作,重者造成事故,損失生命財產。軟件測試是保證軟件質量的最重要的手段。什么是軟件測試?1983年IEEE定義為:使用人工或自動手段來運行或測定某個系統的過程,其目的在于檢驗它是否滿足規定的需求或是弄清預期結果與實際結果之間的差別。 現代的軟件開發工程是將整個軟件開發過程明確的劃分為幾個階段(參見[6]的論述),將復雜問題具體按階段加以解決。這樣,在軟件的整個開發過程中,可以對每一階段提出若干明確的監控點,作為各階段目標實現的檢驗標準,從而提高開發過程的可見度和保證開發過程的正確性。經驗證明,軟件的質量不僅是體現在程序的正確性上,它和編碼以前所做的需求分析,軟件設計密切相關。軟件使用中出現的錯誤,不一定是編程人員在編碼階段引入的,很可能在程序設計,甚而需求分析時就埋下了禍因。這時,對錯誤的糾正往往不能通過可能會誘發更多錯誤的簡單的修修補補,而必須追溯到軟件開發的最初階段。這無疑增大了軟件的開發費用。因此,為了保證軟件的質量,我們應該著眼于整個軟件生存期,特別是著眼于編碼以前的各開發階段的工作。這樣,軟件測試的概念和實施范圍必須擴充,應該包括在整個開發各階段的復查、評估和檢測。由此,廣義的軟件測試實際是由確認、驗證、測試三個方面組成(注:本文對后面用廣義測試概念處不另加標識): 確認:是評估將要開發的軟件產品是否是正確無誤、可行和有價值的。比如,將要開發的軟件是否會滿足用戶提出的要求,是否能在將來的實際使用環境中正確穩定的運行,是否存在隱患等。這里包含了對用戶需求滿足程度的評價。確認意味著確保一個待開發軟件是正確無誤的,是對軟件開發構想的檢測。 驗證:是檢測軟件開發的每個階段、每個步驟的結果是否正確無誤,是否與軟件開發各階段的要求或期望的結果相一致。驗證意味著確保軟件是會正確無誤的實現軟件的需求,開發過程是沿著正確的方向在進行。 測試:與狹隘的測試概念統一。通常是經過單元測試、集成測試、系統測試三個環節。 在整個軟件生存期(參見[6]中的劃分),確認、驗證、測試分別有其側重的階段。確認主要體現在計劃階段、需求分析階段、也會出現在測試階段;驗證主要體現在設計階段和編碼階段;測試主要體現在編碼階段和測試階段。事實上,確認、驗證、測試是相輔相成的。確認無疑會產生驗證和測試的標準,而驗證和測試通常又會幫助完成一些確認,特別是在系統測試階段。 面向對象技術是一種全新的軟件開發技術,正逐漸代替被廣泛使用的面向過程開發方法,被看成是解決軟件危機的新興技術。面向對象技術產生更好的系統結構,更規范的編程風格,極大的優化了數據使用的安全性,提高了程序代碼的重用,一些人就此認為面向對象技術開發出的程序無需進行測試。應該看到,盡管面向對象技術的基本思想保證了軟件應該有更高的質量,但實際情況卻并非如此,因為無論采用什么樣的編程技術,編程人員的錯誤都是不可避免的,而且由于面向對象技術開發的軟件代碼重用率高,更需要嚴格測試,避免錯誤的繁衍。因此,軟件測試并沒有面向對象編程的興起而喪失掉它的重要性。 從1982年在美國北卡羅來納大學召開首次軟件測試的正式技術會議至今,軟件測試理論迅速發展,并相應出現了各種軟件測試方法,使軟件測試技術得到極大的提高。然而,一度實踐證明行之有效的軟件測試對面向對象技術開發的軟件多少顯得有些力不從心。尤其是面向對象技術所獨有的多態,繼承,封裝等新特點,產生了傳統語言設計所不存在的錯誤可能性,或者使得傳統軟件測試中的重點不再顯得突出,或者使原來測試經驗認為和實踐證明的次要方面成為了主要問題。例如: 在傳統的面向過程程序中,對于函數 面向對象程序的結構不再是傳統的功能模塊結構,作為一個整體,原有集成測試所要求的逐步將開發的模塊搭建在一起進行測試的方法已成為不可能。而且,面向對象軟件拋棄了傳統的開發模式,對每個開發階段都有不同以往的要求和結果,已經不可能用功能細化的觀點來檢測面向對象分析和設計的結果。因此,傳統的測試模型對面向對象軟件已經不再適用。針對面向對象軟件的開發特點,應該有一種新的測試模型。
一、面向對象測試模型(Object-Orient Test Model) 面向對象的開發模型突破了傳統的瀑布模型,將開發分為面向對象分析(OOA),面向對象設計(OOD),和面向對象編程(OOP)三個階段。分析階段產生整個問題空間的抽象描述,在此基礎上,進一步歸納出適用于面向對象編程語言的類和類結構,最后形成代碼。由于面向對象的特點,采用這種開發模型能有效的將分析設計的文本或圖表代碼化,不斷適應用戶需求的變動。針對這種開發模型,結合傳統的測試步驟的劃分,本文建議一種整個軟件開發過程中不斷測試的測試模型,使開發階段的測試與編碼完成后的單元測試、集成測試、系統測試成為一個整體。測試模型如下圖所示: |
|
0 面向對象編程
OOA Test:面向對象分析的測試 OOD Test:面向對象設計的測試 OOA Test和OOD Test 是對分析結果和設計結果的測試,主要是對分析設計產生的文本進行,是軟件開發前期的關鍵性測試。OOP Test主要針對編程風格和程序代碼實現進行測試,其主要的測試內容在面向對象單元測試和面向對象集成測試中體現。面向對象單元測試是對程序內部具體單一的功能模塊的測試,如果程序是用C++語言實現,主要就是對類成員函數的測試。面向對象單元測試是進行面向對象集成測試的基礎。面向對象集成測試主要對系統內部的相互服務進行測試,如成員函數間的相互作用,類間的消息傳遞等。面向對象集成測試不但要基于面向對象單元測試,更要參見OOD或OOD Test結果(詳見后敘述)。面向對象系統測試是基于面向對象集成測試的最后階段的測試,主要以用戶需求為測試標準,需要借鑒OOA或OOA Test結果。 盡管上述各階段的測試構成一相互作用的整體,但其測試的主體、方向和方法各有不同,且為敘述的方便,本文接下來將從OOA,OOD,OOP,單元測試,集成測試,系統測試六個方面分別介紹對面向對象軟件的測試。 對由OOA,OOP,OOD這三個開發階段所構成的開發模型、各階段應該完成的目標以及結果報告的形式等詳細介紹,已經超出本文內容,請參見[1]。 二、面向對象分析的測試(OOA Test) 傳統的面向過程分析是一個功能分解的過程,是把一個系統看成可以分解的功能的集合。這種傳統的功能分解分析法的著眼點在于一個系統需要什么樣的信息處理方法和過程,以過程的抽象來對待系統的需要。而面向對象分析(OOA)是"把E-R圖和語義網絡模型,即信息造型中的概念,與面向對象程序設計語言中的重要概念結合在一起而形成的分析方法"(參見[1]),最后通常是得到問題空間的圖表的形式描述。 OOA直接映射問題空間,全面的將問題空間中實現功能的現實抽象化。將問題空間中的實例抽象為對象(不同于C++中的對象概念),用對象的結構反映問題空間的復雜實例和復雜關系,用屬性和服務表示實例的特性和行為。對一個系統而言,與傳統分析方法產生的結果相反,行為是相對穩定的,結構是相對不穩定的,這更充分反映了現實的特性。OOA的結果是為后面階段類的選定和實現,類層次結構的組織和實現提供平臺。因此,OOA對問題空間分析抽象的不完整,最終會影響軟件的功能實現,導致軟件開發后期大量可避免的修補工作;而一些冗余的對象或結構會影響類的選定、程序的整體結構或增加程序員不必要的工作量。因此,本文對OOA的測試重點在其完整性和冗余性。 盡管OOA的測試是一個不可分割的系統過程,為敘述的方便,鑒于[2]中Coad方法所提出的OOA實現步驟,對OOA階段的測試劃分為以下五個方面: |
|
1 對認定的對象的測試: OOA中認定的對象是對問題空間中的結構,其他系統,設備,被記憶的事件,系統涉及的人員等實際實例的抽象(參見[2])。對它的測試可以從如下方面考慮: 1.1 認定的對象是否全面,是否問題空間中所有涉及到的實例都反映在認定的抽象對象中。 2 對認定的結構的測試 在Coad方法中,認定的結構指的是多種對象的組織方式,用來反映問題空間中的復雜實例和復雜關系。認定的結構分為兩種:分類結構和組裝結構。分類結構體現了問題空間中實例的一般與特殊的關系,組裝結構體現了問題空間中實例整體與局部的關系。 2.1 對認定的分類結構的測試可從如下方面著手: 2.1.1 對于結構中的一種對象,尤其是處于高層的對象,是否在問題空間中含有不同于下一層對象的特殊可能性,即是否能派生出下一層對象。 2.2 對認定的組裝結構的測試從如下方面入手: 3 對認定的主題的測試 主題是在對象和結構的基礎上更高一層的抽象,是為了提供OOA分析結果的可見性,如同文章對各部分內容的概要。對主題層的測試應該考慮以下方面: 3.1 貫徹George Miller 的"7+2"原則(參見[3]),如果主題個數超過7個,就要求對有較密切屬性和服務的主題進行歸并。 3.2 主題所反映的一組對象和結構是否具有相同和相近的屬性和服務。 3.3 認定的主題是否是對象和結構更高層的抽象,是否便于理解OOA結果的概貌(尤其是對非技術人員的OOA 結果讀者)。 3.4 主題間的消息聯系(抽象)是否代表了主題所反映的對象和結構之間的所有關聯。 4 對定義的屬性和實例關聯的測試 屬性是用來描述對象或結構所反映的實例的特性。而實例關聯是反映實例集合間的映射關系。對屬性和實例關聯的測試從如下方面考慮: 4.1 定義的屬性是否對相應的對象和分類結構的每個現實實例都適用。 5 對定義的服務和消息關聯的測試 定義的服務,就是定義的每一種對象和結構在問題空間所要求的行為。由于問題空中實例間必要的通信,在OOA 中相應需要定義消息關聯(詳細內容參見[3])。對定義的服務和消息關聯的測試從如下方面進行: 5.1 對象和結構在問題空間的不同狀態是否定義了相應的服務。 三、面向對象設計的測試(OOD Test) 通常的結構化的設計方法,用的"是面向作業的設計方法,它把系統分解以后,提出一組作業,這些作業是以過程實現系統的基礎構造,把問題域的分析轉化為求解域的設計,分析的結果是設計階段的輸入"(參見[1])。 而面向對象設計(OOD)采用"造型的觀點",以OOA為基礎歸納出類,并建立類結構或進一步構造成類庫,實現分析結果對問題空間的抽象。OOD 歸納的類,可以是對象簡單的延續,可以是不同對象的相同或相似的服務。由此可見,OOD不是在OOA上的另一思維方式的大動干戈,而是OOA的進一步細化和更高層的抽象。所以,OOD與OOA 的界限通常是難以嚴格區分的。OOD確定類和類結構不僅是滿足當前需求分析的要求,更重要的是通過重新組合或加以適當的補充,能方便實現功能的重用和擴增,以不斷適應用戶的要求。因此,對OOD的測試,本文建議針對功能的實現和重用以及對OOA結果的拓展,從如下三方面考慮: 1 對認定的類的測試 OOD認定的類可以是OOA中認定的對象,也可以是對象所需要的服務的抽象,對象所具有的屬性的抽象。認定的類原則上應該盡量基礎性,這樣才便于維護和重用。參考[4][5]中所提出的一些準則,測試認定的類: 1.1 是否含蓋了OOA中所有認定的對象。 2 對構造的類層次結構的測試 為能充分發揮面向對象的繼承共享特性,OOD的類層次結構,通?;贠OA中產生的分類結構的原則來組織,著重體現父類和子類間一般性和特殊性。兩者概念上的差異,請參見[1]。在當前的問題空間,對類層次結構的主要要求是能在解空間構造實現全部功能的結構框架。為此,測試如下方面: 2.1 類層次結構是否含蓋了所有定義的類。 3 對類庫支持的測試 對類庫的支持雖然也屬于類層次結構的組織問題,但其強調的重點是再次軟件開發的重用。由于它并不直接影響當前軟件的開發和功能實現,因此,將其單獨提出來測試,也可作為對高質量類層次結構的評估。參照[9]中提出的準則,擬訂測試點如下: 3.1 一組子類中關于某種含義相同或基本相同的操作,是否有相同的接口(包括名字和參數表)。 四、面向對象編程的測試(OOP Test) 典型的面向對象程序具有繼承、封裝和多態的新特性,這使得傳統的測試策略必須有所改變。封裝是對數據的隱藏,外界只能通過被提供的操作來訪問或修改數據,這樣降低了數據被任意修改和讀寫的可能性,降低了傳統程序中對數據非法操作的測試。繼承是面向對象程序的重要特點,繼承使得代碼的重用率提高,同時也使錯誤傳播的概率提高。繼承使得傳統測試遇見了這樣一個難題:對繼承的代碼究竟應該怎樣測試?(參見面向對象單元測試)。多態使得面向對象程序對外呈現出強大的處理能力,但同時卻使得程序內"同一"函數的行為復雜化,測試時不得不考慮不同類型具體執行的代碼和產生的行為。 面向對象程序是把功能的實現分布在類中。能正確實現功能的類,通過消息傳遞來協同實現設計要求的功能。正是這種面向對象程序風格,將出現的錯誤能精確的確定在某一具體的類。因此,在面向對象編程(OOP)階段,忽略類功能實現的細則,將測試的目光集中在類功能的實現和相應的面向對象程序風格,主要體現為以下兩個方面(假設編程使用C++語言)。 ☆ 數據成員是否滿足數據封裝的要求 1 數據成員是否滿足數據封裝的要求 數據封裝是數據和數據有關的操作的集合。檢查數據成員是否滿足數據封裝的要求,基本原則是數據成員是否被外界(數據成員所屬的類或子類以外的調用)直接調用。更直觀的說,當改編數據成員的結構時,是否影響了類的對外接口,是否會導致相應外界必須改動。值得注意,有時強制的類型轉換會破壞數據的封裝特性。例如: 2 類是否實現了要求的功能 類所實現的功能,都是通過類的成員函數執行。在測試類的功能實現時,應該首先保證類成員函數的正確性。單獨的看待類的成員函數,與面向過程程序中的函數或過程沒有本質的區別,幾乎所有傳統的單元測試中所使用的方法,都可在面向對象的單元測試中使用。具體的測試方法在面向對象的單元測試中介紹。類函數成員的正確行為只是類能夠實現要求的功能的基礎,類成員函數間的作用和類之間的服務調用是單元測試無法確定的。因此,需要進行面向對象的集成測試。具體的測試方法在面向對象的集成測試中介紹。需要著重聲明,測試類的功能,不能僅滿足于代碼能無錯運行或被測試類能提供的功能無錯,應該以所做的OOD結果為依據,檢測類提供的功能是否滿足設計的要求,是否有缺陷。必要時(如通過OOD結仍不清楚明確的地方)還應該參照OOA的結果,以之為最終標準。 五、面向對象的單元測試(OO Unit Test) 傳統的單元測試是針對程序的函數、過程或完成某一定功能的程序塊。沿用單元測試的概念,實際測試類成員函數。一些傳統的測試方法在面向對象的單元測試中都可以使用。如等價類劃分法,因果圖法,邊值分析法,邏輯覆蓋法,路徑分析法,程序插裝法等等,方法的具體實現參見[6]。單元測試一般建議由程序員完成。 用于單元級測試進行的測試分析(提出相應的測試要求)和測試用例(選擇適當的輸入,達到測試要求),規模和難度等均遠小于后面將介紹的對整個系統的測試分析和測試用例,而且強調對語句應該有100%的執行代碼覆蓋率。在設計測試用例選擇輸入數據時,可以基于以下兩個假設: 1. 如果函數(程序)對某一類輸入中的一個數據正確執行,對同類中的其他輸入也能正確執行。該假設的思想可參見[6]中介紹的等價類劃分。 2. 如果函數(程序)對某一復雜度的輸入正確執行,對更高復雜度的輸入也能正確執行。例如需要選擇字符串作為輸入時,基于本假設,就無須計較于字符串的長度。除非字符串的長度是要求固定的,如IP地址字符串。 · if (-1==write (fid, buffer, amount)) error_out(); · 按程序的設計,使用函數strrchr()查找最后的匹配字符,但誤程序中寫成了函數strchr(),使程序功能實現時查找的是第一個匹配字符。 · 程序中將if (strncmp(str1,str2,strlen(str1)))誤寫成了 因此,在做測試分析和設計測試用例時,應該注意面向對象程序的這個特點,仔細的進行測試分析和設計測試用例,尤其是針對以函數返回值作為條件判斷選擇,字符串操作等情況。 面向對象編程的特性使得對成員函數的測試,又不完全等同于傳統的函數或過程測試。尤其是繼承特性和多態特性,使子類繼承或過載的父類成員函數出現了傳統測試中未遇見的問題。在[7]中,Brian Marick 給出了二方面的考慮: 1. 繼承的成員函數是否都不需要測試? 根據[7]中的論述,對父類中已經測試過的成員函數,兩種情況需要在子類中重新測試:a)繼承的成員函數在子類中做了改動;b)成員函數調用了改動過的成員函數的部分。例如: 假設父類Bass有兩個成員函數:Inherited()和Redefined(),子類Derived只對Redefined()做了改動?! erived::Redefined()顯然需要重新測試。對于Derived::Inherited(),如果它有調用Redefined()的語句(如:x=x/Redefined()),就需要重新測試,反之,無此必要。 2. 對父類的測試是否能照搬到子類? 援用上面的假設,Base::Redefined()和Derived::Redefined()已經是不同的成員函數,它們有不同的服務說明和執行。對此,照理應該對 Derived::Redefined()重新測試分析,設計測試用例。但由于面向對象的繼承使得兩個函數有相似,故只需在 Base::Redefined()的測試要求和測試用例上添加對Derived::Redfined()新的測試要求和增補相應的測試用例。例如: Base::Redefined()含有如下語句 在原有的測試上,對Derived::Redfined()的測試只需做如下改動:將value==0的測試結果期望改動;增加value==88的測試。 多態有幾種不同的形式,如參數多態,包含多態,過載多態。包含多態和過載多態在面向對象語言中通常體現在子類與父類的繼承關系,對這兩種多態的測試參見上述對父類成員函數繼承和過載的論述。包含多態雖然使成員函數的參數可有多種類型,但通常只是增加了測試的繁雜。對具有包含多態的成員函數測試時,只需要在原有的測試分析和基礎上擴大測試用例中輸入數據的類型的考慮。對類為粒度進行面向對象的單元測試,可參考[10]中關于如何從MtSS生成測試用例的說明。 六、面向對象的集成測試(OO Integrate Test) 傳統的集成測試,是由底向上通過集成完成的功能模塊進行測試,一般可以在部分程序編譯完成的情況下進行。而對于面向對象程序,相互調用的功能是散布在程序的不同類中,類通過消息相互作用申請和提供服務。類的行為與它的狀態密切相關,狀態不僅僅是體現在類數據成員的值,也許還包括其他類中的狀態信息。由此可見,類相互依賴極其緊密,根本無法在編譯不完全的程序上對類進行測試。所以,面向對象的集成測試通常需要在整個程序編譯完成后進行。此外,面向對象程序具有動態特性,程序的控制流往往無法確定,因此也只能對整個編譯后的程序做基于黑盒子的集成測試。 面向對象的集成測試能夠檢測出相對獨立的單元測試無法檢測出的那些類相互作用時才會產生的錯誤?;趩卧獪y試對成員函數行為正確性的保證,集成測試只關注于系統的結構和內部的相互作用。面向對象的集成測試可以分成兩步進行:先進行靜態測試,再進行動態測試。 靜態測試主要針對程序的結構進行,檢測程序結構是否符合設計要求?,F在流行的一些測試軟件都能提供一種稱為"可逆性工程"的功能,即通過原程序得到類關系圖和函數功能調用關系圖,例如International Software Automation 公司的Panorama-2 for Windows95、Rational公司的Rose C++ Analyzer等,將"可逆性工程"得到的結果與OOD的結果相比較,檢測程序結構和實現上是否有缺陷。換句話說,通過這種方法檢測OOP是否達到了設計要求。 動態測試設計測試用例時,通常需要上述的功能調用結構圖、類關系圖或者實體關系圖為參考,確定不需要被重復測試的部分,從而優化測試用例,減少測試工作量,使得進行的測試能夠達到一定覆蓋標準。測試所要達到的覆蓋標準可以是:達到類所有的服務要求或服務提供的一定覆蓋率;依據類間傳遞的消息,達到對所有執行線程的一定覆蓋率;達到類的所有狀態的一定覆蓋率等。同時也可以考慮使用現有的一些測試工具來得到程序代碼執行的覆蓋率。 具體設計測試用例,可參考下列步驟: 值得注意,設計測試用例時,不但要設計確認類功能滿足的輸入,還應該有意識的設計一些被禁止的例子,確認類是否有不合法的行為產生,如發送與類狀態不相適應的消息,要求不相適應的服務等。根據具體情況,動態的集成測試,有時也可以通過系統測試完成。 七、面向對象的系統測試(OO System Test) 通過單元測試和集成測試,僅能保證軟件開發的功能得以實現。但不能確認在實際運行時,它是否滿足用戶的需要,是否大量存在實際使用條件下會被誘發產生錯誤的隱患。為此,對完成開發的軟件必須經過規范的系統測試。換個角度說,開發完成的軟件僅僅是實際投入使用系統的一個組成部分,需要測試它與系統其他部分配套運行的表現,以保證在系統各部分協調工作的環境下也能正常工作。在后面對ZXM10收發臺系統測試的敘述可以看到,其他的系統設備(如監控臺,圖象臺,E1接入設備,攝像頭等)如何配合收發臺的系統測試。 系統測試應該盡量搭建與用戶實際使用環境相同的測試平臺,應該保證被測系統的完整性,對臨時沒有的系統設備部件,也應有相應的模擬手段。系統測試時,應該參考OOA分析的結果,對應描述的對象、屬性和各種服務,檢測軟件是否能夠完全"再現"問題空間。系統測試不僅是檢測軟件的整體行為表現,從另一個側面看,也是對軟件開發設計的再確認。 這里說的系統測試是對測試步驟的抽象描述。它體現的具體測試內容包括: · 功能測試:測試是否滿足開發要求,是否能夠提供設計所描述的功能,是否用戶的需求都得到滿足。功能測試是系統測試最常用和必須的測試,通常還會以正式的軟件說明書為測試標準。 · 強度測試:測試系統的能力最高實際限度,即軟件在一些超負荷的情況,功能實現情況。如要求軟件某一行為的大量重復、輸入大量的數據或大數值數據、對數據庫大量復雜的查詢等。 · 性能測試:測試軟件的運行性能。這種測試常常與強度測試結合進行,需要事先對被測軟件提出性能指標,如傳輸連接的最長時限、傳輸的錯誤率、計算的精度、記錄的精度、響應的時限和恢復時限等。 · 安全測試:驗證安裝在系統內的保護機構確實能夠對系統進行保護,使之不受各種非常的干擾。安全測試時需要設計一些測試用例試圖突破系統的安全保密措施,檢驗系統是否有安全保密的漏洞。 · 恢復測試:采用人工的干擾使軟件出錯,中斷使用,檢測系統的恢復能力,特別是通訊系統?;謴蜏y試時,應該參考性能測試的相關測試指標。 · 可用性測試:測試用戶是否能夠滿意使用。具體體現為操作是否方便,用戶界面是否友好等。 · 安裝/卸載測試(install/uninstall test)等等。 系統測試需要對被測的軟件結合需求分析做仔細的測試分析,建立測試用例。 |
原文轉自:http://www.anti-gravitydesign.com