我們會在寫程式之前寫測試,分分秒秒如此。我們會永遠保存這些測試,並頻繁地全部一起執行。我們也會從客戶的視角導出測試。

測試是把信心變成產出物#

唉,沒人想談測試。測試是軟體開發裡那個醜陋的繼子。

問題是:每個人都知道測試很重要,每個人都知道自己測得不夠,而且我們感覺得到——專案沒有應有的順利,我們覺得多測一點也許有幫助。但我們一翻開測試的書,就立刻陷在各式各樣的測試種類與方法裡,根本不可能全部做完還剩下時間開發。

XP 的測試是這樣的:

  • 程式設計師每次寫程式碼時都認為它會運作。所以每次他們認為某段程式碼會運作,就把那份信心從虛空中取出來,變成一個放進程式裡的產出物。這份信心是給他們自己用的;而因為它就在程式裡,其他人也能使用這份信心。
  • 客戶也一樣。每次他們想到程式該做的某件具體的事,就把它變成另一塊放進程式裡的信心。現在他們的信心與程式設計師的信心並存於其中——程式變得越來越有信心。

一位測試專業人員看了 XP 的測試大概會竊笑。這不是一個熱愛測試的人的作品,恰恰相反——這是一個熱愛「讓程式能動」的人的作品。

所以你該寫的,是那些幫助程式開始運作、並讓程式持續運作的測試。不多不少。

順著人性寫測試#

記得那條原則「順著人性、不逆著人性」。作者說那正是他讀過的測試書籍犯的根本錯誤:它們的前提是測試位於開發的中心——你必須做這個測試、那個測試,喔對了還有另外那個。

如果我們希望程式設計師與客戶寫測試,最好把這個過程弄得盡可能無痛。要認清:測試只是儀器(instrumentation),大家真正在乎的是被測量的系統行為本身,而不是測試本身。

如果不用測試也能開發,我們一分鐘之內就會把所有測試都倒掉。

延伸:釋放你心中的豬

Massimo Arnoldi 寫道:

不幸的是,至少對我(而且不只我)而言,測試違反人性

如果你釋放心中的那頭豬,你會發現自己在沒有測試的情況下寫程式。然後過了一陣子,當你理性的那一面獲勝,你才停下來開始寫測試。

你也提過,結對程式設計降低了兩位夥伴同時釋放自己那頭豬的機率

測試必須「隔離」且「自動」#

XP 中你必須寫的測試,具備兩項性質:

隔離(isolated)#

每個測試都不與你寫的其他測試互動,這樣就能避免「一個測試失敗連帶造成一百個失敗」的問題。

這種事發生五次、十次之後,你還會仔細留意那些測試嗎?門都沒有。

自動(automatic)#

測試在壓力升高、人們工作過度、人的判斷開始失靈時最有價值。 所以測試必須是自動的——給出一個關於「系統行為是否正常」的、無條件的大拇指朝上或朝下

該測什麼#

要把所有東西都測到,卻不讓測試變得跟程式碼一樣複雜且易錯,是不可能的;而什麼都不測(就隔離、自動測試的意義而言)則是自殺。那麼,在所有你能想像去測的東西裡,你該測什麼?

如果一段程式碼簡單到不可能壞掉,而且你也量到它實際上確實沒壞過,那你就不該為它寫測試。

如果有人叫你「絕對什麼都要測」,你很快就會發現自己寫的大部分測試毫無價值;而如果你和作者一樣,你就會乾脆不寫了——「這測試玩意兒是給鳥吃的。」

測試是一場賭注#

  • 一個測試你沒預期會通過、卻通過了——那你最好去查清楚它為什麼會通過,因為程式碼比你聰明
  • 一個測試你預期會通過、卻壞了

兩種情況你都學到了東西。而軟體開發就是學習——你學得越多,你開發得越好。

所以,如果可以,你只會寫那些會有回報的測試。但既然你無法知道哪些測試會有回報(如果你知道,那你早就知道了,也就沒在學任何東西),你就寫那些「可能」有回報的測試

測著測著,你會反思哪類測試傾向有回報、哪類沒有,然後多寫有回報的、少寫沒回報的。

誰來寫測試#

測試來自兩個來源:程式設計師客戶

程式設計師:逐方法寫#

程式設計師在以下情況寫測試:

  • 方法的介面稍有不清——在寫方法之前先寫測試
  • 介面清楚,但你想像實作會有一丁點複雜——在寫方法之前先寫測試
  • 你想到一個「程式碼照現況該能運作」的不尋常情境——寫一個測試來溝通這個情境
  • 你後來發現一個問題——寫一個測試把問題隔離出來
  • 你正要重構某段程式碼,卻不確定它該有什麼行為,而且該行為面向還沒有測試——先寫測試

如果有一個單元測試壞了,團隊裡沒有人有比修好測試更重要的工作。因為一旦測試壞掉,你要修好它得付出未知的工作量——可能只花一分鐘,也可能花一個月,你不知道。

而正因為單元測試的撰寫與執行都由程式設計師掌控,他們能讓測試與程式碼完全同步

客戶:逐故事寫#

客戶要問自己的問題是:「在我有信心這個故事已經完成之前,有哪些東西必須被檢查?」他們想出的每個情境,都變成一個測試——在這裡是功能測試

所以:單元測試的度量是二元的——100% 或死;功能測試的度量則必然基於百分比。

隨著時間過去,你會期待功能測試分數上升到接近 100%。接近發布時,客戶必須為失敗的功能測試分類——有些比其他的更重要、更該修。

測試人員的角色#

客戶通常無法自己寫功能測試。 他們需要有人幫忙:先把他們的測試資料翻譯成測試,並隨時間打造工具,讓客戶能自己撰寫、執行與維護自己的測試。

這就是為什麼任何規模的 XP 團隊都至少配置一位專職測試人員。測試人員的工作是把客戶有時模糊的測試想法,翻譯成真實、自動、隔離的測試;他也以客戶啟發的測試為起點,發展出更可能弄壞軟體的變化版本

即使你有一位專職測試人員——那種樂趣來自「弄壞據說已經做完的軟體」的人——他們也在與寫測試的程式設計師相同的經濟框架中工作:測試人員也在下注,希望碰上一個「該失敗卻成功」或「該成功卻失敗」的測試。

所以測試人員同樣在隨時間學習寫出越來越好、越來越可能有回報的測試。他絕不是待在那裡盡可能多產出測試的。

其他種類的測試#

單元測試與功能測試是 XP 測試策略的核心,但偶爾其他測試也有意義。一支 XP 團隊會辨認出「自己正在走偏、而某種新測試可能有幫助」的時刻,例如:

  • 平行測試(Parallel test)——設計來證明新系統與舊系統運作完全一致。更準確地說,這個測試呈現新系統與舊系統的差異,好讓業務人員做出業務決策:差異何時小到可以把新系統送上正式環境。
  • 壓力測試(Stress test)——設計來模擬最糟糕的負載。適合效能特性不易預測的複雜系統。
  • 猴子測試(Monkey test)——設計來確保系統面對毫無道理的輸入時仍表現得合理。