歡迎來到測試與除錯的世界!
你有沒有試過寫好一段程式碼,按下「執行」後……卻什麼都沒有發生?或者更慘,它出現了一些莫名其妙的結果?別擔心——每一位程式設計師,從新手到 Google 的專家,都曾遇過這種情況!測試 (Testing) 與 除錯 (Debugging) 就是電腦科學中的「偵探技能」。在這章節中,我們將學習如何找出錯誤(Bug)、如何修復它們,以及如何從一開始就預防錯誤發生。讓我們開始吧!
1. 程式錯誤的類型
在解決問題之前,我們必須先釐清問題的性質。你將會遇到三大類的錯誤:
語法錯誤 (Syntax Errors)
你可以把它想像成程式碼中的「文法錯誤」。如果你拼錯了關鍵字,例如寫成 prnt() 而不是 print(),或者在 if 語句的結尾忘了加冒號,電腦甚至無法啟動你的程式。因為它根本聽不懂你的指令。
執行時期錯誤 (Run-time Errors)
程式開始執行了,但卻在運行過程中突然「崩潰」。常見的例子是試圖除以零 \( (x / 0) \),或是嘗試打開一個不存在的檔案。指令本身的邏輯沒錯,但電腦在運行時撞上了一道無法跨越的「磚牆」。
邏輯錯誤 (Logic Errors)
這些是最棘手的!程式完美運行且不會崩潰,但輸出結果卻是錯的。例如,如果你想計算 \( 2 + 2 \),卻不小心輸入成 2 * 2,電腦會給你 4。它完全執行了你給的指令,但你給的指令本身就是錯的!邏輯錯誤是由程式設計師找出,而不是電腦。
快速回顧:
• 語法錯誤: 電腦聽不懂「語言」。
• 執行時期錯誤: 電腦在運行時「絆倒了」。
• 邏輯錯誤: 電腦完美執行指令,但指令內容錯誤。
2. 尋找「Bug」(除錯技巧)
我們該如何找出問題出在哪呢?以下是你偵探工具包中最有效的法寶:
手動模擬 (Manual Dry Run) 與 追蹤表 (Trace Tables)
手動模擬 (Manual Dry Run) 是指你拿出紙筆,親自扮演電腦的角色。你逐行閱讀程式碼,並記錄變數數值的變化。我們使用 追蹤表 (Trace Table) 來整理這些變化。
例子: 如果你寫了一個累加數字的迴圈,你的追蹤表欄位可以設為「迴圈計數器」和「總計變數」。這能幫助你精確找出邏輯在第幾個步驟失敗。
使用輸出敘述 (Print Statements)
有時候你需要「X 光視力」來觀察程式內部發生了什麼。透過在不同的步驟插入 print() 敘述,你可以檢查變數是否存有你預期的數值。
小貼士:如果你的程式執行到一半停止,試著加上 print("已到達第 1 步") 來查看程式運行到哪裡中斷!
回溯法 (Backtracking)
如果你在程式的最後發現了錯誤,回溯法意味著從發現錯誤的位置開始,向後檢查程式碼,以找出錯誤的源頭。
漸進式測試 (Incremental Testing) 與 註解掉代碼 (Commenting Out)
漸進式測試是指先寫一小段程式碼並測試它,然後才進入下一部分。千萬不要一次寫 100 行!如果你有一大段程式碼無法運作,你可以把其中的部分程式碼註解掉(在 Python 中使用 # 符號),以隔離出導致問題的區塊。
關鍵重點: 不要只盯著螢幕想找出錯誤。請善用追蹤表來釐清邏輯、用 print 敘述來查看「即時」數據,並將程式拆分成小區塊來測試!
3. 資料驗證:檢查輸入
計算機科學中有句名言:「垃圾進,垃圾出」(Garbage In, Garbage Out, GIGO)。如果你的程式期望輸入「年齡」,但使用者輸入了「香蕉」,程式就會崩潰。資料驗證 (Data Validation) 是由電腦執行的檢查,確保輸入的資料在處理前是「合理」或「有效」的。
常見的驗證檢查:
• 存在性檢查 (Presence check): 確保資料確實被輸入(欄位沒有留空)。
• 範圍檢查 (Range check): 檢查數值是否在特定限制內(例如,年齡必須介於 0 到 120 之間)。
• 長度檢查 (Length check): 檢查輸入是否具有正確的字元數(例如,密碼必須至少 8 個字元)。
• 格式檢查 (Format check): 確保資料符合特定模式(例如,郵遞區號格式)。
• 存在性檢查 (Existence check): 檢查該資料是否已存在於系統中(例如,檢查使用者名稱是否已被註冊)。
• 檢核碼 (Check digit): 在數字(如 ISBN 或條碼)後加上的一個額外數字,利用數學公式驗證數字是否輸入正確。
發現無效資料該怎麼辦?
• 對於互動式輸入(使用者正在輸入時):程式應顯示錯誤訊息,並要求重新輸入。
• 對於非互動式輸入(如讀取檔案):程式通常應該結束執行或記錄錯誤,因為無法要求檔案提供「更佳」的資料。
4. 設計測試案例
為了 100% 確保你的程式運作正常,你需要使用不同類型的資料進行測試。這些稱為 測試案例 (Test Cases)。假設你正在測試一個接受 0 到 100 分考試成績的程式。
1. 正常資料 (Normal Data)
應該毫無問題地被接受的資料。
例子:25, 50, 85。
2. 邊界資料 (Boundary/Extreme Data)
處於允許範圍「邊緣」的資料。邏輯錯誤往往就藏在這裡!
例子:0 和 100(允許的最小值和最大值)。
3. 錯誤資料 (Error/Invalid Data)
程式應該拒絕的資料。這用來測試你的驗證機制是否有效。
例子:-5, 105, "abc"。
你知道嗎? 很多 Bug 的產生是因為程式設計師忘了測試邊界資料。他們測試了「50」是否有效,卻忘了檢查程式是否能準確接受「0」或「100」!
快速回顧箱:
設計測試時,請務必選擇:
1. 中間範圍的資料 (正常資料)
2. 極限範圍的資料 (邊界資料)
3. 完全錯誤的資料 (錯誤資料)
總結清單
如果覺得內容很多,不用擔心!只要記住這些核心重點:
• 使用 追蹤表 (Trace Tables) 來逐行推敲程式碼。
• 語法錯誤是文法問題;邏輯錯誤是結果問題。
• 資料驗證可以防止「垃圾」資料進入你的程式。
• 永遠要用 正常、邊界和錯誤 資料進行測試。
• 使用 print() 敘述來觀察程式運行時變數的狀態!