軟體測試就是挑Bug?也許你有認知偏差
“什麼是軟體測試?”這個看似簡單的一個問題,其實也是最難的問題。說它簡單,是因為這是一個基本的問題,做軟體測試工作多年的小夥伴,自然知道什麼是軟體測試。說它難,是因為“軟體測試”有很多內涵,要了解其全部內涵,並非那麼容易。如果我們去問軟體研發人員什麼是軟體測試,得到的答案可能五花八門,人們對軟體測試有不同的理解。現在最常見的理解就是:軟件測試就是找bug、發現缺陷。
但也有人會認為軟體測試就是:
- 檢查軟體產品是否符合設計要求;
- 驗證軟體產品需求、設計和實現的一致性;
- 確認軟體產品是否滿足使用者的實際需求;
- 對軟體產品質量的全面評估;
- 提供軟體產品質量資訊;
- 揭示軟體產品的質量風險;
- 投入較低的保障性成本極大地降低劣質成本;
- 驗證與確認;
- 調查、分析和比較;
- 不斷探索;
……
有太多的理解,而且都沒有錯,只是看問題的角度不一樣。雖然回答問題時,也容易脫口而出,不會仔細斟酌,只看到軟體測試的一面,沒有系統地分析“什麼是軟體測試”。
下面我們就好好討論“什麼是軟體測試”,因為有什麼理解就有什麼行動。有正確的理解,就有正確的操作;相反,有錯誤的理解,就有錯誤的操作。所以,先幫助讀者對“軟體測試”建立正確、全面的認識,構建起一個完整的“軟體測試”輪廓,不至於陷入“盲人摸象”的困境,對軟體測試有片面的理解。然後,我們再展開流程、方法、技術和實踐的討論。也就是在全面討論“全程軟體測試”之前,咱們需要找到共同語言,即對軟體測試的一些基本概念達成共識,為後面的溝通掃除障礙。
軟體測試基本認知——正反思維
什麼是軟體測試?人們常常回答:軟體測試就是發現軟體產品中的bug(缺陷)。也有人說,不對,軟體測試是驗證軟體產品特性是否滿足使用者的需求。實際上,上述回答都沒錯,是對軟體測試的正反兩個方面的解釋。
早期,人們更多的是將“測試”看作是對產品的“檢驗”,檢查軟體的每個功能是否執行正常。正如1983年Bill Hetzel將軟體測試定義為:“軟體測試就是一系列活動,這些活動是為了評估一個程式或軟體系統的特性或能力,並確定其是否達到了預期結果。”從這個定義中,至少我們可以看到以下兩點。
- 測試試圖驗證軟體是“工作的”,也就是驗證軟體功能執行的正確性。
- 測試的活動是以人們的“設想”或“預期的結果”為依據。這裡的“設想”或“預期的結果”是指需求定義、軟體設計的結果。
但同時我們知道,軟體測試有一條原則:測試是不能窮盡的。測試會面對大量的測試資料、測試場景或程式碼路徑等,測試也只是一個樣本實驗,不能證明軟體是正確的,只能說明發現的缺陷的確是缺陷。但如果沒有發現問題,並不能說明問題就不存在,而是至今未發現軟體中所潛在的問題。正如《軟體測試的藝術》一書作者Glenford J. Myers所說,測試不應該著眼於驗證軟體是工作的,相反,應該用逆向思維去發現儘可能多的錯誤。他認為,從心理學的角度看,如果將 “驗證軟體是工作的”作為測試的目的,非常不利於測試人員發現軟體的錯誤。因此,1979年他給出了軟體測試的不同的定義:“測試是為了發現錯誤而執行一個程式或者系統的過程。”從這個定義可以看出,假定軟體總是存在缺陷的(事實上也是如此)、有錯誤的,測試就是為了發現缺陷,而不是證明程式無錯誤。
從這個定義延伸出去,一個成功的測試是發現了軟體問題的測試,否則測試就沒有價值。這就如同一個病人(因為是病人,假定確實有病),到醫院去做相應的檢查,結果沒有發現問題,那說明這次體檢是失敗的,浪費了病人的時間和金錢。以逆向思維方式引導人們證明軟體是“不工作的”,會促進我們不斷思考開發人員對需求理解的誤區、不良的習慣、程式程式碼的邊界、無效資料的輸入等,找到系統的薄弱環節或識別出系統複雜的區域,目標就是發現系統中各種各樣的問題。
人類的活動具有高度的目的性,建立適當的目標具有顯著的心理作用。如果測試目的是為了證明程式裡面沒有錯誤,潛意識裡就可能不自覺地朝這個方向去做。在進行測試的過程中,就不會刻意選擇一些儘量使程式出錯的測試資料,而選擇一些常用的資料,測試容易通過,而不容易發現問題。如果測試的目的是要證明程式中有錯,那我們會設法選擇一些易於發現程式錯誤的測試資料,這樣,更早、更快地發現缺陷。畢竟開發人員力求構造軟體,以正向思維方式為主,所以逆向思維方式可以提升我們的測試效率。
逆向思維也有不利的一面,容易陷於區域性的深度測試,缺乏廣度。因為覺得某個地方有缺陷,就對這個地方進行測試,然後不斷深入下去,這樣容易忽視一些區域。雖然那些地方產生的缺陷不多,但如果產生了嚴重缺陷,也是我們不能承受的。所以正向思維也是有價值的,它會督促針對軟體系統的所有功能點,逐個驗證其正確性,哪個功能越重要越要進行檢驗。正向思維會讓我們的測試更有廣度——良好的測試覆蓋面。
為了做好測試,既要有深度,又要有廣度;既要有效率,又要有測試工作自身完整的質量。所以,我們應該將正向思維和逆向思維有機地結合起來,做到效率和質量的平衡。換句話說,當我們需要效率時,更多采用逆向思維,當我們需要測試廣度來確保完整的測試質量時,則多采用正向思維。這種平衡還體現在不同的應用領域,例如國防、航天、銀行等關鍵性軟體系統,承受不了系統的任何一次失效。因為這些失效完全有可能導致災難性的事件,所以強調驗證(verify),以保證非常高的軟體質量。而一般的商業應用軟體或服務,質量目標設定在“使用者可接受水平”,以降低軟體開發成本,加快軟體釋出速度,有利於市場的擴張,則可以強調逆向思維,儘快找出大部分缺陷。
從狹義測試到廣義測試
前面提到Glenford J. Myers,他早期給軟體測試的簡單定義是:“程式測試是為了發現錯誤而執行程式的過程”,也體現出當時對軟體測試的認識非常具有侷限性。這也是受軟體開發瀑布模型的影響,認為軟體測試是程式設計之後的一個階段。只有等待程式碼開發出來之後,通過執行程式,像使用者那樣操作軟體發現問題,這就是“動態測試”。
對於需求階段產生的缺陷,在不同階段發現和修復的成本是不一樣的。如果在需求階段發現需求方面的缺陷並進行修復,只要修改需求文件,其成本很低。需求階段產生的缺陷,如果在需求階段沒有發現,等待設計完成之後才被發現,就需要修改需求和設計,成本增大。需求階段產生的缺陷,如果在需求和設計階段都沒有發現,等待程式碼寫完之後才被發現,就需要修改需求、設計、程式碼,成本就更大。設計上的問題,在設計階段被發現,只要修改設計,如果在後期發現,返工的路徑就變長了,其修復的成本自然就增大。缺陷發現得越遲,其修復的成本就越高,如圖1-1所示,呈現了不同階段產生的缺陷在不同階段修復的成本,所以這要求我們儘早發現缺陷。
圖1-1 不同階段產生的缺陷在不同階段修復的成本
為了儘早發現缺陷,我們有必要將軟體測試延伸到需求、設計階段,即對軟體產品的階段性成果——需求定義文件、設計技術文件進行評審或驗證。這不同於軟體質量保證(Quality Assurance,QA),雖然QA側重評審,但它重點評審流程、評審管理,包括對需求、設計、編碼和測試過程規範性的評審。而這裡提到的需求和設計的評審依舊是對軟體產品的檢驗或驗證,只是需求文件和設計文件只是軟體產品的階段性產品。如果按照“軟體=程式+文件+資料結構”這樣的定義,需求文件和設計文件等也屬於軟體的組成部分,軟體測試自然也包括需求和設計的驗證。
基於上述考慮,將早期的動態測試延伸到靜態測試,即從狹義的軟體測試發展到廣義的軟體測試。
- 狹義的軟體測試:動態測試——執行程式而進行的測試,測試只是程式設計之後的階段,這也是由傳統的瀑布模型而決定的。
- 廣義的軟體測試:動態測試+靜態測試,將需求評審、設計評審、程式碼評審(含程式碼的靜態分析)等也納入軟體測試工作之中。這也使“軟體測試”不再停留在程式設計之後的某個階段上,而成為貫穿整個軟體研發週期的質量保證活動,這也是本書“全程軟體測試”的最早立意所在。
靜態測試就是在不執行軟體系統時對軟體或階段性成果進行評審,包括需求評審、設計評審、程式碼評審等。引入靜態測試,就可以儘早地發現問題,把問題消滅在萌芽之中,將每個階段產生的缺陷及時清除,極大地提高產品的質量,有效地降低企業的成本。
基於質量的認知
軟體測試雖然不能等同於軟體質量保證(SQA),但它是軟體質量保證的主要手段之一。當我們討論軟體測試時,絕對離不開“質量”。基於質量的認識,軟體測試就是對軟體產品的質量評估,提高軟體產品有關的質量資訊。即使從1.1節中我們認為軟體測試就是發現軟體產品中的bug(缺陷),哪什麼是“缺陷”呢?簡單地說,缺陷就是質量的對立面,一切違背質量的問題都可以看作軟體缺陷(雖然從專業術語來仔細辨析的話,會將問題分為“內在錯誤,外部失效”等)。所以要理解軟體測試,就必須理解軟體質量。
說起“質量”這個概念,我們都很熟悉,會說“壞的質量會怎樣怎樣,好的質量會怎樣怎樣”,但讓我們給出質量的正式定義,可能不是容易的事情。我們也可以查國際標準,瞭解如何給質量下定義。例如IEEE Std 829-2008定義質量就是系統、元件或過程滿足特定需求的程度,滿足客戶/使用者需求或期望的程度。滿足程度越高,質量就越好。例如,從軟體需求定義文件來看,它所描述的需求和客戶實際業務需求越吻合,將來實現的軟體越有可能滿足客戶的業務需求,也意味著需求文件的質量越高。但這樣說,還是比較寬泛,很難衡量質量。那究竟如何評估質量?從哪些維度來衡量質量呢?這就引出質量模型。基於質量模型,我們可以清楚質量有哪些屬性(或維度),然後針對這些屬性逐個地進行評估,不需要對軟體質量進行整體評估,相當於按質量的各個維度來進行評估、各個擊破。
過去將軟體質量分為內部質量、外部質量和使用質量,像程式碼的規範性、複雜度、耦合性等可以看作是內部質量,內部質量和外部質量共用一個質量模型。現在國際/國家標準將內部質量和外部質量合併為產品質量。產品質量可以認為是軟體系統自身固有的內在特徵和外部表現,而使用質量是從客戶或使用者使用的角度去感知到的質量。因為質量是相對客戶而存在,沒有客戶就沒有質量,質量是客戶的滿意度。過去認為,內部質量影響外部質量、外部質量影響使用質量,而使用質量依賴外部質量、外部質量依賴內部質量。今天可以理解為產品質量影響使用質量,而使用質量依賴產品質量。
1.產品質量
根據國際標準IEEE 24765-2010,產品質量是指在特定的使用條件下產品滿足明示的和隱含的需求所明確具備能力的全部固有特性。而根據ISO 25010:2011標準,質量模型從原來的6個特性增加到8個特性,新增加了“安全性、相容性”。如圖1-2所示,藍色標註的內容屬於新增加或改動的內容。這裡的安全性是指資訊保安性(Security),原來放在“功能性”下面,但現在絕大部分產品都是網路產品,安全性越來越重要,所以有必要作為單獨的一個維度來度量。今天系統互聯互通已經很普遍,其次終端裝置越來越多,除了傳統的PC機,還有許多智慧移動裝置,如手機、平板電腦、智慧手環、智慧手錶等,這些都要求系統具有良好的相容性。這些特性就對應著測試型別,如功能測試、效能測試(效率)、相容性測試、安全性測試等。
圖1-2 ISO 25010 2016 產品質量模型
- 功能適應性(functional suitability):軟體所實現的功能達到其設計規範和滿足使用者需求的程度,強調正確性、完備性、適合性等。
- 效率(efficiency):在指定條件下,軟體對操作所表現出的時間特性(如響應速度)以及實現某種功能有效利用計算機資源(包括記憶體大小、CPU佔用時間等)的程度,區域性資源佔用高通常是效能瓶頸存在;系統可承受的併發使用者數、連線數量等,需要考慮系統的可伸縮性。
- 相容性(compatibility),涉及共存和互操作性,共存要求軟體能給與系統平臺、子系統、第三方軟體等相容,同時針對國際化和本地化進行合適的處理。 互操作性要求系統功能之間的有效對接,涉及API和檔案格式等。
- 易用性(usability):對於一個軟體,使用者學習、操作、準備輸入和理解輸出所做努力的程度,如安裝簡單方便、容易使用、介面友好,並能適用於不同特點的使用者,包括對殘疾人、有缺陷的人能提供產品使用的有效途徑或手段(即可達性)。
- 可靠性(reliability):在規定的時間和條件下,軟體所能維持其正常的功能操作、效能水平的程度/概率,如成熟性越高,可靠性就越高;用平均失效前時間(Mean Time To Failure,MTTF)或平均故障間隔時間(Mean Time Between Failures,MTBF)來衡量可靠性。
- 安全性(security):要求其資料傳輸和儲存等方面能確保其安全,包括對使用者身份的認證、對資料進行加密和完整性校驗,所有關鍵性的操作都有記錄(log),能夠審查不同使用者角色所做的操作。它涉及保密性、完整性、不可抗抵賴性、可稽核性、真實性。
- 可維護性(maintainability):當一個軟體投入執行應用後,需求發生變化、環境改變或軟體發生錯誤時,進行相應修改所做努力的程度。它涉及模組化、可複用性、易分析性、易修改性、易測試性等
- 可移植性(portability):軟體從一個計算機系統或環境移植到另一個系統或環境的容易程度,或者是一個系統和外部條件共同工作的容易程度。它涉及適應性、可安裝性、可替換性。
2.使用質量
從ISO/IEC 25010標準看,軟體測試還要關注使用質量,如圖1-3所示。在使用質量中,不僅包含基本的功能和非功能特性,如功能(有效與有用)、效率(效能)、安全性等,還要求使用者在使用軟體產品過程中獲得愉悅,對產品信任,產品也不應該給使用者帶來經濟、健康和環境等風險,並能處理好業務的上下文關係,覆蓋完整的業務領域。
圖1-3 使用質量的屬性描述
為了便於理解使用質量,下面舉3個例子。
【例1-1】我自己親身經歷的例子。我在手機上安裝了一個英語學習軟體,自動下載該款軟體用到的多個語音庫(如新概念英語、六級英語等),它在我講課時,但並沒有判斷我手機連線的是Wi-Fi還是3G/4G,造成我的流量大大超過套餐額度,產生了額外的300元流量費。從功能上看,自動下載是一個不錯的功能,但有很大的經濟風險,在使用質量上有明顯缺陷。
【例1-2】當我們玩遊戲,沉醉於某款遊戲,從產品本身質量屬性看。是一個好產品,沒有問題。但從使用質量看,會有損於玩家的健康,有健康風險,所以需要設定防沉迷功能。
【例1-3】當我們使用百度地圖、滴滴打車等軟體時,往往是在大街上。如果站在人行道或安全地方使用沒問題,但是如果一面橫穿馬路一面還在使用,就有安全風險。這類軟體應該給予提示,否則它們要承擔相應的風險責任。
基於風險的認知
因為沒有辦法證明軟體是正確的,軟體測試本身總是具有一定的風險性,所以軟體測試被認為是對軟體系統中潛在的各種風險進行評估的活動。從風險的觀點看,軟體測試就是對軟體產品質量風險的不斷評估,引導軟體開發工作,進而將最終釋出的軟體所存在的風險降到最低。基於風險的軟體測試認知主要體現在兩點上:
軟體測試不僅僅停留在單個缺陷上,要從所發現的問題看到(分析出)某類質量風險或某個具有潛在風險的區域。
軟體測試被看作是一個動態的質量監控過程,對軟體開發全過程進行檢測,隨時發現不健康的徵兆,及時評估新的風險,設定新的監控基準,不斷地持續下去。
基於風險對測試的認知,會強調測試的持續性,持續地進行測試,寫幾行程式碼就要做測試、實現一個功能就要對這個功能進行測試,開發和測試相伴而行。這種認知特別適合敏捷開發模式下的測試——敏捷測試。在敏捷開發中,軟體測試就能被解釋為對軟體產品質量的持續評估。在敏捷方法中,不僅提倡持續整合,而且提倡持續測試,持續整合實際上也是為了持續測試。
基於風險對測試的認知還不斷提醒我們:在盡力做好測試工作的前提下,工作有所側重,在風險和開發週期限制上獲得平衡。首先評估測試的風險,每個功能出問題的概率有多大?根據Pareto原則(也叫80/20原則),哪些功能是使用者最常用的20%功能?如果某個功能有問題,其對使用者的影響又有多大?然後根據風險大小確定測試的優先順序。優先順序高的功能特性,測試優先得到執行。一般來講,針對使用者最常用的20%功能(優先順序高)的測試會得到完全地、充分地執行,而低優先順序功能的測試(另外使用者不常用的80%功能)就可能由於時間或經費的限制,測試的要求降低、減少測試工作量。
基於社會的認知
軟體不同於硬體,軟體一般都是應用系統,常常和人們的娛樂、事務處理、商業活動、社群交流等緊密聯絡在一起,所以軟體具有很強的社會性,所以有必要把心理學、人類學和社會學等引入到軟體測試中。軟體測試不僅僅是技術活動,而且是社會、心理等綜合性活動,軟體測試是跨學科的(inter-disciplinary)活動,以系統為焦點(systems-focused),通過不斷調查(investigative)和講故事(storytelling)的方式完成軟體質量的評估。
通過軟體測試的社會性認知,強調測試人員的思維能力和探索能力,強調測試的有效性和可靠性,在測試中要理解使用者的行為、人們活動的背景和目的(上下文關係),不斷觀察,不斷學習,發現和質量相關的資訊(差異或質疑),從客戶利益、業務特性出發來守護產品的價值。
也正是由於軟體測試的社會性,需要對軟體產品的易用性、免於風險的程度、上下文覆蓋等進行驗證。在易用性測試中,人們常常進行A/B測試,給出不同的解決方案(UI佈局、功能設計等),向不同的使用者群釋出產品,來檢測哪個解決方案更受使用者喜歡。
基於經濟的認知
一般來說,一個軟體產品沒有經過測試是不會發布(release)、不會部署(deploy)到產品線上,或者說,不敢釋出、不敢上線。因為在當前的開發模式和開發技術情況下,人們開發的軟體存在嚴重的缺陷絕對是大概率事件。如果沒有經過測試,就釋出出去,可能軟體根本不能用、不好用,或者用起來出現各種各樣的問題,使用者滿意度很低,給產品造成負面影響,甚至給客戶帶來嚴重的經濟損失或影響到使用者的生命安全。
從經濟觀點看,軟體缺陷會給企業帶來成本,這個成本就叫劣質成本(Cost of Poor Quality,COPQ)。基於經濟的認知,軟體測試就是通過投入較低的保障性成本來降低劣質成本,幫助企業獲得利潤。高質量不僅是有競爭力,而且是帶來良好的經濟收益的。例如蘋果手機就是以其高質量獲得比其他品牌手機更高的利潤率。據相關媒體統計資料看,蘋果智慧手機在高階手機市場只佔四分之一,但利潤佔到一半。
測試的經濟觀點就是如何以最小的代價獲得更高的收益,這也要求軟體測試儘早開展工作,發現缺陷越早,返工的工作量就越小,所造成的損失就越小。所以,從經濟觀點出發,測試不能在軟體程式碼寫完之後才開始,而是從專案啟動的第一天起,測試人員就參與進去,儘快儘早地發現更多的缺陷,並督促和幫助開發人員修正缺陷。
基於標準的認知
軟體測試被視為“驗證(Verification)”和“有效性確認(Validation)”這兩類活動構成的整體,缺一不可。如果只做到其中一項,測試是不完整的。
- “驗證”是檢驗軟體是否已正確地實現了產品規格書所定義的系統功能和特性。驗證過程提供證據表明軟體相關產品與所有生命週期活動的要求相一致,即驗證軟體實現(即交付給客戶的產品)是否達到了軟體需求定義和設計目標。
- “有效性確認”是確認所開發的軟體是否滿足使用者實際需求的活動。因為軟體需求定義和設計可能就不對,上述一致性不能保證軟體產品符合客戶的實際需求,而且客戶的需求也是在變化的,當需求定義是半年前確定的,這種變化的可能性就比較大。
對驗證和確認有不同的解釋。簡單地說,單元測試、整合測試和系統測試都可以理解為“驗證”,都是基於需求定義文件和設計規格說明書文件來進行驗證;而驗收測試則在使用者現場、由使用者共同參與進行,可以理解為“有效性確認”,因為之前的需求定義和設計都可能存在錯誤,研發團隊沒有正確理解使用者的原意(使用者的真實期望),僅僅根據需求定義文件和設計規格說明書文件來完成測試,並不能代表所實現的功能特性是使用者真正想要的。而在驗收測試中,使用者參與進來,是可以確認所實現的功能特性是否是使用者真正想要的。
另一種解釋是根據圖1-4所示的V模型,驗證是架構設計評審、詳細設計評審和程式碼評審/單元測試,分別驗證架構設計是否和需求一致、詳細設計是否和架構設計一致、程式碼是否和詳細設計一致,用左邊帶箭頭的粗虛線表示。而有效性確認則是整合測試、系統測試、驗收測試,如中間帶箭頭的細虛線表示。
圖1-4 軟體研發的V模型
另一種解釋是根據圖1-4所示的V模型,驗證是架構設計評審、詳細設計評審和程式碼評審/單元測試,分別驗證架構設計是否和需求一致、詳細設計是否和架構設計一致、程式碼是否和詳細設計一致,用左邊帶箭頭的粗虛線表示。而有效性確認則是整合測試、系統測試、驗收測試,如中間帶箭頭的細虛線表示。
[美] 朱少民 著
本書系統地總結了過去十年中軟體測試發生的變化,濃縮了作者許多寶貴的軟體測試經驗。本書首先介紹對於軟體測試的不同看法,全程軟體測試的思想,軟體測試的基礎設施與TA框架、團隊能力建設;然後逐步深入到測試的計劃、設計、執行、持續反饋和改進;接著,討論全程測試的思想,包括全程靜態測試、全程效能測試、全程安全性、全程建模、全程視覺化。本書最後展望了軟體測試的未來。
本書適合軟體測試人員閱讀,也可作為相關專業人士的參考指南