軟體測試:巨集觀視角

殷亮發表於2015-05-13

決定的內容總是具體的,因此無法預計;它總得由人去發明。

——讓-保羅•薩特(Jean-Paul Sartre) ①

巨集觀問題

檢驗一個軟體系統所需要的測試是不可窮盡的,因為我們不可能遍歷客戶的所有可能操作,或者說即使能夠窮舉這些可能的操作,並且我們在實驗室所進行的測試與客戶所做的現場操作步驟完全一樣,但我們仍只能說這是不完全相同的兩個場景,就像古希臘哲學家赫拉克利特(Heraclitus)的名言:人不能兩次踏入同一條河流。場景的每一次執行既相同又不完全相同,而時空的不可窮盡則是測試證明的本質障礙。

我們既存在又不存在。

當認識到我們不可能證明一個無窮的場景集合時,軟體測試就成了一門有關選擇的科學:其核心內容便是研究如何從無窮集合中挑選一個有限的集合來對軟體系統進行測試。在這裡,我們將測試選擇的這一根本問題視為巨集觀問題,並將在下文中展開更為詳細地分析;而將關於測試我們知道什麼以及不知道什麼的問題,劃歸到哲學視角,這已在上一篇論文中得到了比較全面的探討②。

測試的比較

我們必須承認的是,假如真能夠從證明的角度來看待軟體測試的話,那麼一切與測試相關的理論無疑都將是純粹的和精緻的,同時其明確的結果也滿足了人對於預期、秩序與簡單的追求;但我們仍不得不放棄它,因為在我們有限的生命與有限的理性裡,我們不大可能解決歸納與證明問題。也可以說,通過放棄對證明的奢求,我們因而得以迴避了一個無法解決的問題,也不再被無窮集合所困擾。但是,這樣的選擇並非是沒有代價的:一方面,與測試相關的理論變得不那麼簡潔和優雅,而是不可避免的略顯晦澀;另一方面,當我們繞過證明這一不可征服的高山時,卻與另一難題狹路相逢。

這一難題就是對於不完備的測試,我們如何比較兩種測試設計——也就是兩個不同測試子集的優劣。在將測試視為一種證明時,因為我們的目的是證明所有場景,所以除了完全集合,任何不完全子集都是不完整的。而如果比較的是兩個不同子集,則只要子集內部不存在冗餘,那麼兩個子集的比較便是簡單的元素數比較。因此可以說,在證明的世界裡,這一難題並不存在;但是,當我們從證明的世界裡走出時,我們卻不得不面對這一難題的糾纏。

同一個受測系統的兩種測試設計哪一種更好,這並不是一個容易的問題,儘管我們可以教條式地回答說:兩相比較,我們選擇“以最少的測試檢驗出最多的缺陷”的那個。然而這個的原則本身就有諸多疑點,在Jorgensen 2002中,保羅•喬根森(Paul Jorgensen)認為測試有效性的最佳解釋是最困難的:“首先,要假定我們知道程式中的所有缺陷。形成死迴圈的是,如果我們知道程式中的所有缺陷就會採取有針對性的措施。由於我們不知道程式中的所有缺陷,因此永遠也不會知道給定方法所產生的測試用例能否發現這些缺陷”③。實際上這裡的困難是,我們不能將最終檢驗出的缺陷數作為評價一個測試設計的標準。試想假如一個包含了1000個測試用例的測試設計,最終結果是隻有其中1個測試用例檢驗出了1個缺陷,另外的999個測試用例均測試通過;而另一個測試設計就僅僅包含了這個檢查出缺陷的測試用例,然後它也同樣地檢驗出了1個缺陷,這時難道我們可以說後一測試設計比前者更好嗎?當然,對於這個特定的軟體實現(哪裡有缺陷,哪裡沒缺陷)來說,後一測試設計的確更有效率,因為它發現了同樣多的缺陷,卻只用了相對於另一測試設計1/1000的投入,完全符合“以最少的測試用例檢驗出最多的缺陷”的標準。但這裡的關鍵是,對測試設計的評價是不能依賴具體的軟體實現的,某一測試用例是否有必要,不能以它最終有沒有檢驗出缺陷來衡量。無論是否檢驗出缺陷,對於測試設計來說這都應該被視為一種偶然、一種對未知。在前面的這個例子裡,我們可以這樣認為:後一種測試設計它僅僅只是偶然地遇到了這麼一個特定的軟體實現——在這個軟體實現裡,正好在它檢驗了的那部分存在缺陷、同時也正好在它沒檢驗的那部分表現正常。因此,我們沒任何理由認為這樣的一種“結果高效”的測試設計是優於其它測試設計的,就像我們不能因為有人購買一注彩票中獎就否定其它投注者的投注方式一樣。對測試設計的評價不應該建立在任何特定的軟體實現的基礎上,因為任何特定的軟體實現在這個不可能精確計算的世界裡都應當被認為是偶然,而最終的缺陷分佈情況也是偶然。也就是說,當我們以結果來評價兩個測試設計時,如果一定要分出優劣,我們也只能說在某種特定的軟體實現與缺陷分佈下,一個測試設計偶然地高效於另一個測試設計。

當然,還有另一種說法,即評價測試設計的高效的標準是“以最少的測試覆蓋到最多的缺陷”。隨著從“檢驗出”到“覆蓋到”的轉變,“缺陷”一詞的意義也隨之變化了,這裡的缺陷一詞就特指潛在可能的缺陷,因而它不是結果論的,也由此避免了對特定軟體實現與缺陷分佈的依賴。但這一標準並不能給我們多大的指導意義,因為如果違背這一標準,則意味著對於同一缺陷我們加入了多餘的測試。但是在什麼情況會出現多餘的測試呢?完全相同的測試肯定算是,但不完全相同的測試呢?比如對於一個接受1~255的輸入,我們設計了5個測試:分別1、2、250、254、255,如果在此基礎上,我們再加入一個測試用來測試輸入3,那麼這個測試算是多餘的嗎?在這裡,除非我們能斷定導致測試輸入3可能失敗的潛在缺陷與其它輸入可能檢驗出的缺陷是源自同一錯誤,否則我們就不能將這個測試視為多餘。但是很顯然,我們並不能做出此類的斷定,因為既然討論的是潛在可能缺陷,那麼我們所能斷言的就只是其結果(缺陷的形式),而不是其原因(錯誤根源)。

因此,我們只能說對於測試設計效率的客觀評估是困難的,不管是遵循什麼樣的標準。當我們試圖比較兩個測試設計時,如果以最終檢驗的缺陷數來衡量,那麼這一評估也就僅僅只是對當前的軟體實現是客觀的,而對於其它可能的實現或缺陷分佈來說則是未知的;另一方面,如果我們用覆蓋的潛在缺陷來衡量,那麼這似乎又是另一種形式的倒退,因為我們必須對兩個缺陷是否源自同樣的錯誤做出斷言,但我們也知道,這一過程既是不可能的、同樣也是不充分的。

測試的模式

選擇的存在,一方面賦予了軟體測試以新的核心與意義,標誌著測試不僅僅只是執行檢測,其更為重要的內涵是做出決策;但另一方面它也使得測試工作者不得不面對著新的困難:即如何做出比較與選擇的問題。在測試學科數十年的發展歷程中,人們發明了各種各樣的測試方法,這些測試方法所基於的假設與側重點並不一樣,但目的都是為測試工作者的選擇提供一定的指導。

在這些方法中,無論是功能性測試還是結構性測試,本質上都是關於選擇的。在功能性測試中,邊界值方法指導我們在邊界與非邊界中作出選擇(例如在測試1~255時,我們選擇輸入1、2,而沒有選擇3);在等價類方法中,我們實際上也是通過劃分互不相交的一組子集,然後從子集中選擇一個元素作為測試輸入;決策表方法同樣是關於選擇的,滿足一個規則的變數可能有許多,但最終我們只會選擇其中一個。而對於結構性測試而言,儘管在方法的立足點與技巧上相異甚遠,但是結構性測試方法的本質上仍然還是選擇:因為使得程式在某一特定路徑上執行的選擇大多數時候並非一個。

因此,我們可以說測試方法簡化了測試選擇,或者說,這些測試方法為我們所遇到的特定的選擇問題提供了成熟的解決方案。比如邊界值方法指導我們在面對一組輸入範圍時,如何選擇測試用例,以更高效地找出系統裡最可能出現的與邊界相關的錯誤;但這一方法同時又對布林變數和大部分GUI操作無解。其它測試方法也是如此,實際上每一種測試方法既有其擅長解決的問題,也有其不適宜的場景。比如,當我們比較功能性測試與結構性測試時,我們就發現:功能測試揭示不了軟體實現了未被描述的行為,而結構性測試則發現不了軟體未實現的被描述的行為。因此,我們可以把測試方法看作是解決特定問題的捷徑,這些捷徑的存在使得我們在面對這些特定問題時能快速做出成熟的選擇,而不需要完全從頭開始思考。建築學家克里斯托夫•亞歷山大(Christopher Alexander)作為模式與模式語言的奠基人,他對模式有如下的定義:“首先描述在我們的環境中反覆出現的問題,然後給出該問題的核心解決方法,以這樣的方式,你可以上百萬次地使用這種解決方法”④,因而我們可以認為模式就是對一類特定問題的抽象與簡化,並給出解決方案。正如建築領域的建築模式與軟體設計中的設計模式一樣,我認為測試方法就是軟體測試領域裡的模式。這類模式的存在,使得測試工作者並不需要徹底弄懂邊界值測試方法的原理(不小於可能會誤寫為大於、不大於可能會誤寫為小於),也能設計出清晰的一致的測試用例集。就像掌握設計模式後,一些新人也能寫出優雅且極具擴充套件性的設計一樣。 相比起深層次理解要解決的問題,應用已有的模式無疑更為簡單;同時,由於模式是建立在前人的經驗上,應用模式顯然能避免無謂的錯誤。因此我們可以這樣理解:模式是一種具備了高度的簡單性與準確性的理論,但它並不具備足夠的普遍性,因為模式原本就是站在普遍性的對面,它針對的就是某類特定的問題。或者我們可以這樣理解,模式犧牲了一定的普遍性,換取了高度的簡單性與準確性。這就是沃倫•桑納葛特(Thorngate 1976)所提出的相對稱的複雜性原理⑤:一個社會理論通常無法同時具備普遍性、準確性以及簡單性。當我們試圖將簡單性與準確性收入囊中的時候,那我們就自動地犧牲了普遍性。反之亦然,當我們說好的測試設計就是“用最少的測試用例檢驗出最多的缺陷”時,實際上我們是陳述了一個普遍的、簡單的觀點,因而當我們發現這個觀點並不那麼準確時,我們也不應該感到意外。

然而,在當今各個領域的研究中所存在的諸多問題,其根源多為不願接受前文中所提及的不可避免的折中選擇,研究者們表現得似乎可以在他們的方法或理論中同時兼顧這三個目標,實現魚與熊掌兼得。甚至在那些獲獎的專案管理書籍中(比如Rothman 2007),我們也能看到一些看似有理並且言之鑿鑿的論點,可是隻要進一步思考這些論點,我們就不難發現它們要麼沒有斷言任何確切的因果關係,要麼斷言了因果關係卻不夠精確。我們必須認識到,軟體專案自是千差萬別,而軟體團隊也是百態紛呈的,再加上技術變革的層出不窮,在這麼一個複雜的領域裡,要想提出一個既簡單清晰、又準確無誤,同時還能放之四海皆準的全新理論無疑是極為困難的。我們必須知道我們想要的是什麼,以及為了得到想要的我們必須犧牲什麼。

就測試方法而言,儘管沒有哪種測試方法能適應所有的問題,但它們所提供的簡單性與準確性依舊是寶貴的,而且也將永遠都是我們在測試設計過程中所能依賴的最重要的工具。然而,藉助測試方法這一工具,我們並不能回答為何如此設計測試的問題。方法不是選擇的原理,因為方法自身也需要原理。因此,當我們決意探究有關測試設計的普遍性原理時,我們就必須超越易於理解的方法論,同時我們也必須作好犧牲簡單性的準備——假如我們並不打算放棄準確性的話。

測試的選擇

如果不存在匱乏,就不存在選擇。如果測試可以零成本地執行,既不需要人力資源成本,也不需要時間成本,那麼測試選擇將沒任何意義。但是正因為人力與時間均是有成本的,所以我們才有需要在不可窮盡的可能測試中做出選擇,選擇其中一部分而放棄餘下的;選擇值得測試的,而放棄不值得測試的。在這裡使用的“值得”一詞,實際上與我們常說的投入回報比,或者經濟學中的邊際收益—邊際成本是一個意思,而邊際收益—邊際成本分析工具仍然是現代選擇邏輯的核心部分。因此,涉及到有關測試的選擇:選擇一部分場景而放棄另一部分場景,選擇某一個場景而放棄另一個場景,最終都可還原成對收益與成本的綜合評估。

在通常語境下,如果我們說測試某一個場景的收益大於另一場景的收益,這意味著什麼呢?如果考慮到測試是一種批判,那麼我們顯然應該選擇更有可能檢測出問題的場景,比如在測試1~255的輸入範圍時,我們在1與2之間選擇1,這是因為我們認為相比起忘記累加,程式設計師更容易犯將不大於寫成小於的錯誤。而當我們在各種環境配置中進行選擇,測試某一種而不去測試另一種時,也是因為我們判斷這樣的選擇相對而言會更有可能檢測出缺陷,或者說至少也是同等可能性的。另一方面,當我們判斷兩種場景都有同樣的可能性檢測出缺陷時,選擇可以是隨意的。比如我們就不會覺得選擇測試輸入10與11會有什麼本質上的差別。但是,當兩個場景具有不同的重要性——也就是說一個場景的故障後果可能嚴重於另一個故障時,即使我們認為兩者具有同等的可能性,我們也會傾向於選擇更為重要的那個場景。根據這個原則,我們往往不會選擇測試終端使用者不會使用或較少使用的環境配置,而在選擇測試主要場景還是擴充套件場景之時,答案也不言而喻的,即使一般來說擴充套件場景似乎更有可能檢測出缺陷。因此,在比較的兩個場景的測試收益時,我們將可能檢測出缺陷的概率,以及缺陷的嚴重程度為依據做出評估:

測試收益 = 檢測出缺陷的可能性 ╳ 檢測出缺陷所能避免的損失

上述公式已能幫助我們對測試選擇形成一個比較直觀的認識了:在檢測出缺陷的可能性相等的情況下,選擇故障後果更嚴重的場景將收益更大;而在兩個故障後果差不多的場景之間,公式指引我們選擇更容易檢測出缺陷的那個。在這兩個變數的共同影響下,我可以認為,每一個測試都對應著一個特定的測試收益值。如果要在兩個可能的測試中做出選擇,那麼在其它條件都相同的前提下,我們選擇收益最大的那個;當兩者的收益無差異時,如何選擇也將是無差異的。

當然,測試收益並非是我們評估的唯一要素,對於測試選擇來說,它必要但並不充分;因為除了測試收益外,還有另外一個不可忽視的因素,那就是測試成本,正如前文所說的,測試不可能零成本地進行。一般來說,測試成本相對而言比較好理解,因為通常我們將其解釋為人月、人天或人時,視之為一種可度量的資源投入。在加入了測試成本這一因素後,我們的分析將更為全面,從效率的角度看,我們希望所選擇的測試收益儘可能地大,同時所付出的成本又儘可能地小。因而,我們有可能會在評估可能的測試成本後,放棄掉一些收益可觀的測試。在這種情況下,並非是該測試收益不夠大,而是因為這一收益在更大的測試成本面前,顯得並不值得。測試是一個獲取資訊的過程,測試能讓我們知道得更多,但在有些時候,資訊的成本有可能會大於無知的成本。

綜合測試收益與測試成本,我們將測試選擇演變成了一個關於效率的問題,也就是說我們將選擇更有效率的測試,並且希望接下來的每一單位測試成本的投入所產生的收益能夠最大化。在進行測試設計時,測試工作者實際上面臨的是一個無比巨大的測試集合(因為有無數的可能場景),我們從零開始,不斷地從集合中挑選出能讓接下來一單位的測試成本投入產生出最大收益的測試用例,之後一直重複這一過程,直到在原集合中再也找不出單位收益能大於單位成本的測試用例。

測試成本與收益

由於我們總是先選擇現存的、能令單位成本收益最大化的測試,因此隨著選擇的持續與投入的增加,單位成本的收益(dr/dc)必將遞減,最終會小於1,並從上方穿過成本收益相等線(dr/dc=1)。這是因為,總會有一些場景是收益小於回報的,此時dr/dc<1。因此,最佳測試投入的選擇就在於收益等於回報的那一點,在這一點上,繼續往前是得不償失的,而後退一點則是未充分最大化收益。上述過程描述了我們對測試用例的理性選擇,如同測試場景的不可窮盡論指出完備的測試是不可能的一樣,測試的效率論認為:完備的測試不僅是不可能的,同時也是不經濟的。

測試的評估

在上文中,我們在儘量避擴音出這樣一種簡單的觀點:即對測試的選擇,實際上就是選擇一切測試收益大於執行成本的測試。從結果上看,這一觀點與我們前面的討論似乎是一致的,兩者最終都包含了所有收益大於成本的測試,也都排除了一切得不償失的場景。但是它們之間存在著一個不明顯但非常關鍵的差異:在這個簡單的觀點中,其核心前提是測試的收益與成本是明確的,同時也是固定的;但在前面的持續選擇理論裡,卻並不要求有這樣的前提。儘管將測試的成本與收益看作是明確的與不變的——這一點既符合我們的直覺也吻合了我們的期望,但是這並不是現實。在現實中,測試的收益既不是客觀明確的,也不是持續不變的。我們以邊界值選擇為例,在一個邊界值測試方法中,我們通常會選擇min、min+、nom、max-、max這五種場景,其中nom項是隨意的,而其它四項是明確的。假如在1~255的測試中,我們可以將200作為nom項,根據“選擇一切收益大於成本的測試”的觀點,我們之所以選擇輸入200這一場景,必定是因為測試它的收益大於其執行成本。但這樣一來,問題就出現了:我們既然認為測試輸入200是有效率的,並將其納入我們的選擇集中,那麼我們又該如何解釋像輸入199、輸入201這些看上去與輸入200並無差異但卻被排除在外的場景呢?因為我們沒有任何理由認為它們在測試收益與執行成本上與輸入200有何不同。

因此,我們有必要將測試的選擇看作是一個持續和動態的過程,在這一過程中,每一個測試的收益都不會是固定和絕對的。它之所以不是絕對的,是因為測試的收益通常不會孤立地存在,它取決於我們已經選擇了哪些測試。同時這一收益也只存在於選擇前,並且隨著我們選擇的完成而變得模糊。比如一個可以在4個瀏覽器上執行的測試用例,當我們在這4個可能的測試場景中做出選擇前,每一個場景都有它的收益值,這個收益值可能因具體瀏覽器的市場份額不同而不同,此時的收益值是當我們只打算從中選擇一個場景時的測試收益。然而一旦我們選擇了其中一個測試場景後,比如使用者數最多的那個,那麼受已選擇的這個場景影響,其它場景的收益值必將有一定程度的降低。因為場景的測試收益部分地取決於發現新問題的可能性,而當測試用例已在某一環境中執行後,我們在另一類似的環境中再執行這個測試用例時能發現新問題的可能性已經大大降低,因此收益值必將小於還未選擇任何類似場景時的收益值。在邊界值問題中也是如此:在我們沒選擇任何一個nom值時,所有的非邊界值都是收益大於成本的,然而一旦我們選擇了一個nom值後,原本還值得測試的那些非邊界全部變得得不償失起來,因為我們很難從它們身上測試出已選的nom所不能測試出的新問題來。因此,測試的收益不是固定不變的,在測試的選擇這一持續的過程中,隨著每一次選擇的完成,未被選擇的測試的收益將被重新賦值,而被選擇的測試的收益也會隨決策過程的進行而失去其獨立性,變成總收益不可分割的一部分。

當然,測試的收益也不可能是客觀明確的。儘管我們在前面已經建立了一個確定的收益公式,但事實上,無論是收益的價值還是收益的可能性,都是建立在預期的基礎之上,它必然是一個向前看的或者事前的概念,因而是不確定的。在面臨不確定性時,實際決策者對於測試收益的評價可能會不同於任何外部觀察者。決策者必須為外部事件賦予主觀概率,而這裡不存在任何可加以客觀決定的概率係數;同時,由於面對的是並不重複的單一事件,因而也沒有任何的統計係數可供利用。在這裡,我們所運用的數學、所建立的公式,實際上僅僅只是一種直觀的語言、一種簡潔的表達方式,目的只是用來說明收益評估過程中的關鍵因果關係。我們對收益的理解和評估,也並不會因為用了數學而更準確或者發現更多。嘗試對單一事件的可能性進行“科學的”評估,實際上在許多學科的歷史上都有誤用這種或然率計演算法的記錄,這類情形正如約翰•穆勒(John Mill)所說,使其成為了“數學真正的恥辱” ⑥。可以這樣認為,由於存在不確定性,我們對收益的價值評價或多或少都是基於主觀的,而這一收益在未來是否發生也是或然的,這種主觀性並不會因為我們使用公式表達而變得客觀,而其發生的或然性也不會因為數學計算的使用而得以消除。正如諾貝爾經濟學獎得主詹姆斯•布坎南(James Buchanan)所指出的:“在一個完全確定的世界裡,不存在決策問題,即便真有‘選擇’存在的話,那麼一臺計算機就完全可以全然處理。只有在不確定的世界中,才會有真正的選擇”⑦。而測試選擇就是這樣的一種選擇。

這些不同的因素都強調了這樣一個事實:對測試的選擇不存在任何簡單的、準確的,同時又是普遍的方法,能讓測試工作者可以一學便會、一蹴而就。相反,測試的選擇是一個複雜的、主觀的過程,我們必須持續地進行的取捨抉擇,並且在每一個選擇點上,既要前瞻又要後顧,既要分析又要猜測。然而,也正是這些不確定性與複雜性的存在、正是選擇的智慧與勇氣在這裡的不可或缺,使得測試既是科學,又是藝術。

測試的成本

測試的收益與成本共同決定了最終的測試選擇,在上文中我們已經完成了對測試收益全方位地探討,而對於測試成本,我們僅僅只是暫時地將其視為資源投入的成本,這樣處理一方面是與人的直覺相符,另一方面也是為了更專注地討論收益問題。當我們把測試成本用人月、人日或者人時來衡量時,我們實際上是把測試成本看成一種量化的會計成本,一個可以事前預測、事後核算的數字。同時,也意味著我們還將其定義成了一種獨立於收益的變數,既不影響收益也不為收益所影響。

然而,成本的概念並沒有這樣簡單,尤其是它與收益之間,存在著某些不同於表面的微妙關係。在經濟學中,海狸與鹿的故事有著極高的出現頻率:“如果在一個以狩獵為生的國度裡,捕殺一隻海狸耗費的勞動通常兩倍於捕殺一頭鹿所耗費的勞動,那麼一隻海狸自然就應當交換兩頭鹿,或者說值兩頭鹿”⑧。上述論斷來自亞當•斯密(Adam Smith),這也概括了古典的交換理論。正常的或自然的交換價值(也就是收益)由相對生產成本(海狸與鹿2:1)決定,這回答了古典經濟學的核心內容。當然,這一理論是有缺陷的,至少從測試成本的角度來看,我們不能因為測試A場景的投入兩倍於B場景,就說測試場景A的收益就應當兩倍於場景B,這顯然是謬論。然而,我們卻可以說,海狸的成本是鹿而鹿的成本是海狸,或者說一個測試的成本就是因執行它而放棄的另一個測試的可能收益,在弗蘭克•奈特(Frank Knight)看來,這一理解是“成本概念中唯一客觀和科學的內容”⑨。一個商品的成本由可替代的或者捨棄的產品價值來衡量,這就是機會成本思想。因此,可以這樣認為,海狸的成本是2頭鹿,而鹿的成本是1/2頭海狸,如果海狸的市場價值剛好是2頭鹿的話,那麼是選擇捕殺海狸還是捕殺鹿並沒有區別。但如果海狸的市場價值小於2頭鹿,那麼人們就不會選擇捕殺海狸了,因為這樣的選擇是收益(1頭海狸)小於成本(2頭鹿)的。

同樣,基於機會成本的思想,當銀行存款年利是5%時,一筆投入100元、一年後收到101元的投資實際上就是不值得的,因為這一收益所面對的成本並非表面上的會計成本100元,而是選擇了這一投資而放棄的潛在收益105元(機會成本)。因此,在測試選擇中,我們倘若將成本簡單地理解成資源的投入便有可能做出錯誤的選擇,因為成本實際上是做出當前選擇而必須放棄的其它選擇的收益。也就是說,當一個人說一種特定的測試是“不值得”的,這並不是說其收益相比起對應的資源投入不值得,而僅僅只是意味著他偏好另外一個測試——如果選擇另一個測試,收益將會更多。

成本就是我們所放棄的收益,我們在測試選擇這一持續的過程中,不斷地做出選擇——選擇收益大於機會成本的測試,一直到最後一個收益大於機會成本的測試。因為機會成本就是另一可能選擇的收益,因此我們又可以將這一過程視為收益與收益之間的比較過程,成本的概念因之淡化,而僅僅是為比較兩個選擇的收益充當橋樑的作用。這一過程的最終結果,與我們在一系列選擇中做出利潤最大化的選擇結果在大多時候是一致的,因此羅納德•科斯(Ronald Coase)認為:“彌補成本和使利潤最大化實際上是表達同一個現象的兩種方式”⑩。但是,機會成本的思想能使我們站得更高、也看得更遠,使得我們可以超出當前專案,看到更為寬廣、更為全域性化的選擇。因為從機會成本的角度看來,將資源投入重新配置到另一專案或者另一型別的投資也是一種可能的選擇。這樣,我們就有可能正確地拒絕那些在當前專案看來有效率、但在全域性上卻並非最好選擇的方案。很明顯,在現實中,我們爭論對某一個軟體的測試是過多還是過少時、爭論某一測試是必要還是沒必要時,往往都是陷入了會計成本的誤區。

小結

在軟體測試領域裡,不存在簡單的問題。尤其是當我們不滿足於簡單方法論,試圖尋求一種更普遍更一般化的選擇理論時,各因素的不確定性與因果關係的複雜性便隨之浮現出來。而對於這些不確定性與複雜性來說,它們既不可能被完全量化,也不可能被徹底消除。我們所能做的,僅僅只是適應與管理這些不確定性與複雜性,而不是假裝其不存在。因為我們知道,引入數學和公式並不會從根本上使問題變簡單,收益公式中有關或然率的計算,在某種意義上僅僅只是藉助數學符號來表示這一有缺陷的知識。它既不擴張、也不拓深,更不補充我們的知識,它只是把這些已知的知識轉變成數學語言。就像經濟學家路德維希•米塞斯(Ludwig Mises)所說:“在評價、選擇和行動中決沒有什麼可度量和可相等的,有的只是等級之差,也即取或舍”⑾。

經過前面的分析,現在我們應該可以輕鬆回答Paul Jorgensen在其經典著作中所提出的“什麼時候測試可以停止”的問題了。答案的關鍵就在於機會成本,機會成本也是一切選擇型問題的核心思想。然而,我們也必須清醒地認識到:我們僅能明確地回答“什麼時候測試可以停止”,這是一個巨集觀的、實證的陳述;但我們無法明確地回答“什麼時候某一軟體的測試可以停止”,因為這涉及到有關收益的主觀判斷,因而不可能存在完全客觀的答案。

註釋

1. Jean-Paul Sartre 《Existentialism is a Humanism》. 1946.

[2]. 見前一篇《軟體測試:哲學視角》.

[3]. Paul Jorgensen. 《Software Testing: A Craftsman’s Approach》. 2002.

[4]. Christopher Alexander. 《A Pattern Language》. 1977.

[5]. Warren Thorngate. 《"In general" vs. "it depends"》. 1976

[6]. John Stuart Mill. 《A System of Logic Ratiocinative and Inductive》. 1936.

[7]. James Buchanan. 《Cost and Choice》. 1999.

[8]. Adam Smith. 《The Wealth of Nations》. 1937.

[9]. Frank Knight. 《A Suggestion for Simplifying the Statement of the General Theory of Price》. 1928

[10]. Ronald Coase. 《Business Organization and the Accountant》. 1938

[11]. Ludwig Mises. 《Human Action: A Treatise On Economics》. 1949

相關文章