軟件測試是一項(xiàng)技術(shù)性工作,但同時也涉及經(jīng)濟(jì)學(xué)和人類心理學(xué)的一些重要因素。

  在理想情況下,我們會測試程序的所有可能執(zhí)行情況,而在大多數(shù)情況下,這幾乎是不可能的。即使一個看起來非常簡單的程序,其可能的輸入與輸出組合可達(dá)到數(shù)百種甚至數(shù)千種,對所有的可能情況都設(shè)計測試用例是不切合實(shí)際的。對一個復(fù)雜的應(yīng)用程序進(jìn)行完全的測試,將耗費(fèi)大量的時間和人力資源,這樣在經(jīng)濟(jì)上是不可行的。

  另外,要成功地測試一個軟件應(yīng)用程序,測試人員也需要有正確的態(tài)度(也許用“愿景”(vision)這個詞會更好一些)。在某些情況下,測試人員的態(tài)度可能比實(shí)際的測試過程本身還要重要。因此,在深入探討軟件測試的本質(zhì)之前(指技術(shù)層面),我們先探討一下軟件測試的心理學(xué)問題。

  測試執(zhí)行得差,其中一個主要原因在于大多數(shù)的程序員一開始把“測試”這個術(shù)語的定義搞錯了。

  他們可能會認(rèn)為:

  “軟件測試是證明軟件不存在錯誤的過程!

  “軟件測試的目的在于證明軟件能夠正確完成其預(yù)定的功能!

  “軟件測試是建立一個‘軟件做了其應(yīng)該做的’信心的過程!

  這些定義都是本末倒置的。

  每當(dāng)測試一個程序時,應(yīng)當(dāng)想到要為程序增加一些價值。通過測試來增加程序的價值,是指測試提高了程序的可靠性或質(zhì)量。提高了程序的可靠性,是指找出并終修改了程序的錯誤。

  因此,不要只是為了證明程序能夠正確運(yùn)行而去測試程序;相反,應(yīng)該一開始假設(shè)程序中隱藏著錯誤(這種假設(shè)對于幾乎所有的程序都成立),然后測試程序,發(fā)現(xiàn)盡可能多的錯誤。

  那么,對于測試,更為合適的定義應(yīng)該是:“測試是為發(fā)現(xiàn)錯誤而執(zhí)行程序的過程”。

  雖然這看起來像是個微妙的文字游戲,但確實(shí)有重要的區(qū)別。理解軟件測試的真正定義,會對成功地進(jìn)行軟件測試有很大的影響。

  人類行為總是傾向于具有高度目標(biāo)性,確立一個正確的目標(biāo)有著重要的心理學(xué)影響。如果我們的目的是證明程序中不存在錯誤,那會在潛意識中傾向于實(shí)現(xiàn)這個目標(biāo);也是說,我們會傾向于選擇可能較少導(dǎo)致程序失效的測試數(shù)據(jù)。另一方面,如果我們的目標(biāo)在于證明程序中存在錯誤,我們設(shè)計的測試數(shù)據(jù)有可能更多地發(fā)現(xiàn)問題。與前一種方法相比,后一種方法會更多地增加程序的價值。

  這種對軟件測試的定義,包含著無窮的內(nèi)蘊(yùn),其中的很多都蘊(yùn)涵在本書各處。舉例來說,它暗示了軟件測試是一個破壞性的過程,甚至是一個“施虐”的過程,這說明為什么大多數(shù)人都覺得它困難。這種定義可能是違反我們愿望的;所幸的是,我們大多數(shù)人總是對生活充滿建設(shè)性而不是破壞性的愿景。大多數(shù)人都本能地傾向于創(chuàng)造事物,而不是將事物破壞。這個定義還暗示了對于一個特定的程序,應(yīng)該如何設(shè)計測試用例(測試數(shù)據(jù))、哪些人應(yīng)該而哪些人又不應(yīng)該執(zhí)行測試。

  為增進(jìn)對軟件測試正確定義的理解,另一條途徑是分析一下對“成功的”和“不成功的”這兩個詞的使用。當(dāng)項(xiàng)目經(jīng)理在歸納測試用例的結(jié)果時,尤其會用到這兩個詞。大多數(shù)的項(xiàng)目經(jīng)理將沒發(fā)現(xiàn)錯誤的測試用例稱為一次“成功的測試”,而將發(fā)現(xiàn)了某個新錯誤的測試稱為“不成功的測試”。

  這又是一次本末倒置。“不成功的”表示事情不遂人意或令人失望。我們認(rèn)為,如果在測試某段程序時發(fā)現(xiàn)了錯誤,而且這些錯誤是可以修復(fù)的,將這次合理設(shè)計并得到有效執(zhí)行的測試稱做是“成功的”。如果本次測試可以終確定再無其他可查出的錯誤,同樣也被稱做是“成功的”。所謂“不成功的”測試,僅指未能適當(dāng)?shù)貙Τ绦蜻M(jìn)行檢查,在大多數(shù)情況下,未能找出錯誤的測試被認(rèn)為是“不成功的”,這是因?yàn)檎J(rèn)為軟件中不包含錯誤的觀點(diǎn)基本上是不切實(shí)際的。

  能發(fā)現(xiàn)新錯誤的測試用例不太可能被認(rèn)為是“不成功的”,也是說,能發(fā)現(xiàn)錯誤證明它是值得設(shè)計的!安怀晒Φ摹睖y試用例,會看到程序輸出正確的結(jié)果而沒發(fā)現(xiàn)任何錯誤。

  我們可以類比一下病人看醫(yī)生的情況,病人因?yàn)樯眢w不舒服而去看醫(yī)生。如果醫(yī)生對病人進(jìn)行了一些檢查和化驗(yàn),卻沒有診斷出任何病因,我們不會認(rèn)為這些檢查和化驗(yàn)是“成功的”,因?yàn)椴∪酥Ц读税嘿F的檢查和化驗(yàn)費(fèi)用,而病狀卻依然如故。病人會因此而質(zhì)疑醫(yī)生的診斷能力。但是,如果醫(yī)生診斷出病人是胃潰瘍,那么這次檢測是“成功的”,醫(yī)生可以開始進(jìn)行相應(yīng)的治療。因此,醫(yī)療行業(yè)會使用“成功的”或“不成功的”來表達(dá)診斷結(jié)果。我們當(dāng)然可以類推到軟件測試中來,當(dāng)我們開始測試某個程序時,它好似我們的病人。

  “軟件測試是證明軟件不存在錯誤的過程”,這個定義會帶來第二個問題。對于幾乎所有的程序而言,甚至是非常小的程序,這個目標(biāo)實(shí)際上也是無法達(dá)到的。

  另外,心理學(xué)研究表明,當(dāng)人們開始一項(xiàng)工作時,如果已經(jīng)知道它是不可行的或無法實(shí)現(xiàn)時,人的表現(xiàn)會相當(dāng)糟糕。舉例來說,如果要求人們在15分鐘之內(nèi)完成星期日《紐約時報》里的縱橫填字游戲,那么我們會觀察到10分鐘之后的進(jìn)展非常小,因?yàn)榇蠖鄶?shù)人都會卻步于這個現(xiàn)實(shí),即這個任務(wù)似乎是不可能完成的。但是如果要求在四個小時之內(nèi)完成填字游戲,我們很可能有理由期望在初10分鐘之內(nèi)的進(jìn)展會比前一種情況下的大。將軟件測試定義為發(fā)現(xiàn)程序錯誤的過程,使得測試是個可以完成的任務(wù),從而克服了這個心理障礙。

  諸如“軟件測試是證明‘軟件做了其應(yīng)該做的’的過程”此類的定義所帶來的第三個問題是,程序即使能夠完成預(yù)定的功能,也仍然可能隱藏錯誤。也是說,當(dāng)程序沒有實(shí)現(xiàn)預(yù)期功能時,錯誤是清晰地顯現(xiàn)出來的;如果程序做了其不應(yīng)該做的,這同樣是一個錯誤。如果我們將軟件測試視作發(fā)現(xiàn)錯誤的過程,而不是將其視為證明“軟件做了其應(yīng)該做的”的過程,我們發(fā)現(xiàn)后一類錯誤的可能性會大很多。

  總結(jié)一下,軟件測試更適宜被視為試圖發(fā)現(xiàn)程序中錯誤(假設(shè)其存在)的破壞性的過程。一個成功的測試用例,通過誘發(fā)程序發(fā)生錯誤,可以在這個方向上促進(jìn)軟件質(zhì)量的改進(jìn)。當(dāng)然,終我們還是要通過軟件測試來建立某種程度的信心:軟件做了其應(yīng)該做的,未做其不應(yīng)該做的。但是通過對錯誤的不斷研究是實(shí)現(xiàn)這個目的的佳途徑。

  有人可能會聲稱“本人的程序完美無缺”(不存在錯誤),針對這種情況建立起信心的好辦法是盡量反駁他,即努力發(fā)現(xiàn)不完美之處,而不只是確認(rèn)程序在某些輸入情況下能夠正確地工作。