一、前言
在前幾天的學習中,我已經逐步完成個人健康習慣追蹤系統的核心功能,包括健康紀錄輸入、資料保存、歷史紀錄查詢、統計分析、圖表呈現,以及習慣目標完成率計算。
然而,程式能夠正常執行,並不代表系統中的所有功能都沒有問題。
例如,使用者可能輸入負數的喝水量、過大的睡眠時數、錯誤的日期,或是沒有填寫必要的資料。如果系統沒有妥善處理這些情況,就可能產生錯誤的統計結果,甚至導致程式中斷。
因此,今天將進入系統測試與除錯階段,學習如何設計測試案例、檢查輸入資料、找出程式錯誤,並確認系統在正常與異常情況下都能適當地回應。
二、學習目標
了解系統測試與程式除錯的基本概念。
設計健康習慣追蹤系統的測試案例。
使用 Python 檢查空白欄位、錯誤格式與不合理數值。
使用 try...except 處理可能發生的錯誤。
驗證 CSV 資料是否能正確讀取與保存。
建立測試紀錄,確認系統是否符合預期。
三、認識系統測試與除錯
系統測試是透過不同的輸入資料與操作方式,確認系統是否能得到預期結果的過程。
除錯則是當程式出現錯誤時,找出問題原因並進行修正。
兩者的目的不同,但在開發過程中密不可分。
例如,當使用者輸入喝水量 2000 毫升時,系統應該能正常保存;當使用者輸入 -500 毫升時,系統則應該拒絕這筆不合理的資料,並顯示清楚的錯誤訊息。
常見的測試類型如下:

透過這些測試,可以在系統正式使用前發現潛在問題,降低資料錯誤與程式中斷的風險。
四、建立資料驗證功能
在健康習慣追蹤系統中,資料驗證是非常重要的一環。
目前系統包含喝水量、睡眠時間與運動時間等數值欄位,因此可以先設定基本的合理範圍。
以下範例使用示範性的輸入限制:
喝水量:0 至 10000 毫升。
睡眠時間:0 至 24 小時。
運動時間:0 至 1440 分鐘。
這些範圍是為了進行程式驗證而設定的輸入限制,不代表醫療上的健康標準。
def validate_health_record(
water_ml,
sleep_hours,
exercise_minutes
):
errors = []
if not 0 <= water_ml <= 10000:
errors.append(
"喝水量必須介於 0 至 10000 毫升。"
)
if not 0 <= sleep_hours <= 24:
errors.append(
"睡眠時間必須介於 0 至 24 小時。"
)
if not 0 <= exercise_minutes <= 1440:
errors.append(
"運動時間必須介於 0 至 1440 分鐘。"
)
return errors
errors = validate_health_record(
water_ml=2000,
sleep_hours=7.5,
exercise_minutes=30
)
if errors:
for error in errors:
print(error)
else:
print("資料驗證通過。")
執行結果:
資料驗證通過。
如果將喝水量改成 -500,程式就會回傳相對應的錯誤訊息。
這種寫法的優點是將驗證規則集中在一個函式中,未來如果需要調整限制,就不必在不同頁面重複修改相同的程式碼。
五、處理非數字與空白輸入
除了數值超出範圍之外,另一個常見問題是使用者輸入了無法轉換成數字的內容。
例如:
water_input = "abc"
try:
water_ml = float(water_input)
print("喝水量:", water_ml)
except ValueError:
print("輸入錯誤,請輸入有效的數字。")
執行結果:
輸入錯誤,請輸入有效的數字。
try...except 可以避免程式遇到無法轉換的內容時直接中斷。
如果使用者透過 Streamlit 的 st.number_input() 輸入數值,元件本身已經會限制部分輸入情況;不過,仍然需要檢查數值是否符合系統設定的合理範圍。
另外,對於文字欄位,例如備註,可以使用 strip() 去除前後空白:
notes = " 今天散步 30 分鐘 "
notes = notes.strip()
print(notes)
執行結果:
今天散步 30 分鐘
這樣可以讓保存的文字更加整潔。
六、實作:在 Streamlit 表單中加入資料驗證
接下來,將資料驗證整合到健康紀錄輸入表單。
這個範例會讓使用者輸入日期、喝水量、睡眠時間與運動時間,並在按下提交按鈕時檢查資料。
import streamlit as st
st.set_page_config(
page_title="健康紀錄資料驗證",
page_icon="🌱"
)
st.title("🌱 健康紀錄資料驗證")
def validate_health_record(
water_ml,
sleep_hours,
exercise_minutes
):
errors = []
if not 0 <= water_ml <= 10000:
errors.append(
"喝水量必須介於 0 至 10000 毫升。"
)
if not 0 <= sleep_hours <= 24:
errors.append(
"睡眠時間必須介於 0 至 24 小時。"
)
if not 0 <= exercise_minutes <= 1440:
errors.append(
"運動時間必須介於 0 至 1440 分鐘。"
)
return errors
with st.form("health_validation_form"):
record_date = st.date_input("紀錄日期")
water_ml = st.number_input(
"喝水量(毫升)",
min_value=0,
max_value=10000,
value=2000,
step=100
)
sleep_hours = st.number_input(
"睡眠時間(小時)",
min_value=0.0,
max_value=24.0,
value=7.0,
step=0.5
)
exercise_minutes = st.number_input(
"運動時間(分鐘)",
min_value=0,
max_value=1440,
value=30,
step=5
)
submitted = st.form_submit_button("檢查資料")
if submitted:
errors = validate_health_record(
water_ml,
sleep_hours,
exercise_minutes
)
if errors:
for error in errors:
st.error(error)
else:
st.success("資料驗證通過!")
st.write("紀錄日期:", record_date)
st.write("喝水量:", water_ml, "毫升")
st.write("睡眠時間:", sleep_hours, "小時")
st.write("運動時間:", exercise_minutes, "分鐘")
程式碼重點說明
使用者可以先完成所有欄位,再按下提交按鈕。這樣可以避免每次調整數值時,網頁就立刻執行一次提交流程。
validate_health_record() 會一次檢查三個數值欄位,並將所有錯誤訊息放進清單中。
這種方式比發現第一個錯誤就停止更方便,因為使用者可以一次看到需要修正的項目。
程式只有在 errors 清單為空時,才會顯示「資料驗證通過」。
這個範例只負責驗證與預覽資料,尚未將資料寫入 CSV。後續整合到完整系統時,應該先完成驗證,再呼叫資料保存函式,避免不合理的資料被寫入檔案。
七、建立系統測試案例
除了測試單一欄位之外,也應該針對整個健康習慣追蹤系統建立測試案例。

測試時,可以依照表格逐項執行,並記錄實際結果。如果實際結果與預期結果不一致,就需要進一步找出問題原因。
需要注意的是,測試案例中的「預期結果」是我們希望系統達成的行為,不代表目前程式一定已經通過所有測試。必須實際執行後,才能確認測試結果。
八、常見錯誤與除錯方式
開發過程中,可能遇到以下幾種問題。
可能原因: 程式執行位置與 health_records.csv 所在位置不同。
處理方式: 確認 CSV 與 app.py 是否位於相同的專案資料夾,或使用正確的檔案路徑。
可能原因: CSV 中的欄位名稱與程式碼不一致,例如將 exercise_minutes 寫成 exercise_time。
處理方式: 檢查 CSV 的第一列欄位名稱,並確認程式使用的名稱完全一致。
可能原因: 原本應該是數字的欄位,卻包含文字或空白。
處理方式: 使用 pd.to_numeric(errors="coerce") 轉換資料,並檢查轉換後的缺失值。
可能原因: 重複紀錄、無效資料或統計範圍定義不一致。
處理方式: 先確認使用了哪些資料,再手動計算少量測試資料,逐步比對程式結果。
可能原因: 語法錯誤、縮排不一致、變數名稱不一致,或函式呼叫順序不正確。
處理方式: 查看終端機的錯誤訊息,從錯誤行數附近開始檢查,不要只依照網頁顯示的錯誤猜測原因。
九、今日成果與學習心得
今天完成了系統測試與除錯的基礎學習,了解如何設計測試案例、檢查健康資料的合理性,以及使用 Python 的例外處理機制避免程式因為錯誤輸入而中斷。
透過這次學習,我了解到系統開發不只是讓功能成功執行,更重要的是確保系統在不同情況下都能維持正確的行為。
例如,正常輸入時應該可以順利處理資料;輸入不合理的數值時,應該提供明確的錯誤訊息;沒有紀錄時,也應該顯示適當的提示,而不是讓使用者看到難以理解的錯誤畫面。
此外,測試案例可以幫助開發者有系統地檢查每個功能,而不是只測試自己最常使用的操作。這樣能更早發現問題,並提高系統的可靠性。
十、下一步學習方向
第二十四天的主題是「改善資料保存與查詢——提升系統的穩定性」。
下一階段將進一步檢查 CSV 資料保存方式、重複紀錄的處理、日期查詢與錯誤處理,讓系統不只具備基本功能,也能更穩定地保存與讀取使用者的健康資料。