空跑測試指的是:讓排程任務走過完整的執行邏輯——讀取資料、做判斷、決定要對外採取哪些動作——但把所有會真正產生後果的步驟(發信、寫資料庫、呼叫外部 API)換成「記錄下來,不實際執行」,最後給你一份清單,列出如果這次是正式執行,會發生哪些事。這跟正式執行的差別只有一件事:有沒有真的觸碰到外部世界。這也是它跟 retry policy、trigger condition 處理的問題層次不同的地方——那兩者處理的是「已經正式上線的任務」遇到失敗或觸發時機該怎麼辦,空跑測試處理的是「還沒正式上線之前」,怎麼在不冒真實風險的情況下,先確認整套邏輯跑起來是不是你預期的樣子。
這件事會被需要,是因為排程任務一旦正式上線,錯誤的代價往往比手動操作高很多——手動寫一封錯誤的信,你在按下送出前還能反悔;排程任務寫錯邏輯,可能是連續好幾天、對好幾百個收件人重複發出同一個錯誤,等到有人發現,傷害已經造成而且難以收回。空跑測試存在的理由,就是把「這個邏輯到底對不對」的驗證時間點,從「正式上線後才發現」提前到「上線前就能看到完整結果」,讓你在不用承擔真實後果的情況下,先看一遍「如果照這個邏輯跑,會發生什麼事」,把明顯的錯誤攔在正式上線之前。
實務上要確認三件事才算完整的空跑測試。第一,確認邏輯的每個判斷分支都真的被跑到,不是只測最順利的那條路徑——如果任務裡有「金額超過某個門檻要特殊處理」的分支,空跑測試要用真的會觸發那個分支的資料去測,不能只用正常情況的資料跑一次就結案。第二,確認會產生副作用的步驟都被正確攔截、改成記錄而非執行——發信步驟要確認真的沒有寄出、寫入步驟要確認資料庫真的沒有異動,這一步本身也需要驗證,因為如果攔截機制本身有漏洞,空跑測試會給你一種「測過了」的安心感,實際上部分步驟悄悄執行了。第三,確認產出的清單夠具體,能讓你光看清單就判斷邏輯對不對,例如清單裡要寫「將發送給 47 位收件人,主旨為某某」,而不是只寫「將發送郵件」,後者的訊息量不足以讓你核對這是不是你要的結果。
對你來說,空跑測試真正的價值在於把「這個邏輯對不對」的除錯成本,從「已經影響到真實資料或真實收件人之後」提前到「還沒造成任何後果的時候」。沒有空跑測試,一個排程任務的邏輯錯誤,要嘛靠事後有人發現異常回頭追查(代價已經發生),要嘛靠上線前你自己盯著程式碼推演每一種可能情況(容易漏掉邊界案例,尤其是你自己沒想到的組合)。有空跑測試,你能實際看到「如果照這個邏輯跑,會送出什麼、寫入什麼」,用眼睛核對而不是用想像推演。要留意的是:空跑測試驗證的是「邏輯本身對不對」,不是「這個邏輯未來會不會遇到沒測過的情況」——正式上線後資料型態、資料量都可能跟測試時不同,空跑測試沒辦法取代 retry policy 或 fallback instruction 這些上線後才需要的機制,三者是不同階段的風險控制,不能只做其中一個就以為完整了。
Terraform 這類基礎設施即程式碼工具的官方文件裡,把 terraform plan 這個指令描述為在真正套用變更前,先產出一份完整清單,列出這次執行會新增、修改、刪除哪些資源,讓使用者在按下真正執行的指令前,能逐項核對這份清單是否符合預期;這個設計背後的邏輯,跟排程任務的空跑測試完全一致——先看過會發生什麼事,再決定要不要真的讓它發生。
優點是能在不造成真實後果的情況下,提前發現邏輯錯誤,把除錯時間點從上線後提前到上線前,大幅降低修正成本;缺點是空跑測試本身需要額外設計「攔截副作用並記錄」的機制,這個機制如果本身有漏洞,會給人一種假的安心感,而且空跑測試只驗證邏輯本身,無法取代上線後才需要的重試與備援機制,兩者必須搭配使用。