「這段爬蟲邏輯有測試,是不是就代表它夠穩固了?」
今天要誠實面對一個沒那麼漂亮的案例。這個系統負責從外部網頁抓取新聞資料的 Crawler 類別,目前只有一個測試案例,而且只驗證了最順利的那條路徑——外部網頁格式正常、回應正常、抓到預期筆數的資料。真正會讓這種整合邏輯出問題的邊界情況,目前完全沒有被涵蓋到。這篇不是要示範「怎麼寫出完美的爬蟲測試」,而是要老實盤點現況、討論這代表什麼風險。
這個系統的 Crawler 類別,對應的測試檔案裡只有一個測試案例:用 Day 16 提到的測試替身搭配一份錄影帶,驗證呼叫抓取新聞的方法之後,回傳了預期筆數的資料。這支測試確實驗證了一件事——「當外部網頁回應格式正常時,這段程式碼能正確解析出資料」。這件事本身有價值,代表基本的解析邏輯是能運作的。
❌ 只看測試通過,以為爬蟲邏輯夠穩固
$ php artisan test --filter=CrawlerTest
✓ fetch
1 passed
看到通過,很容易誤以為這段整合邏輯已經經過充分驗證。
✅ 列出這支測試實際涵蓋跟沒涵蓋的範圍
已涵蓋:外部網頁格式正常時,能正確解析出預期筆數的資料
未涵蓋:
- 外部網頁結構跟預期不一樣時(改版、欄位順序變動)會發生什麼
- 回應是空內容、或格式完全解析不出來時,程式碼會不會直接噴例外
- 部分資料缺漏(例如某幾筆新聞少了某個欄位)時的處理方式
列出來之後會發現,目前唯一驗證的是最理想的那一種情況,而爬蟲類整合邏輯真正容易出問題的地方,往往正是外部網頁「不如預期」的時候——這些情況目前完全沒有測試在把關。
跟外部系統整合的邏輯,寫第一版測試的時候,最直覺的做法就是先錄一次正常運作的流量,證明「這段程式碼至少能處理正常情況」。這一步門檻低、容易完成,也確實提供了基本的信心。但要進一步涵蓋「外部系統回應格式異常時該怎麼辦」,需要先想清楚「異常會長什麼樣子」——這需要對外部系統的行為有更深的觀察,或者真的踩過一次線上事故才會知道要防什麼,門檻明顯更高。這正是為什麼這類整合測試容易停在「先求有」:先求有能建立基本信心,但往往就停在這裡,沒有人回頭補上異常情況的測試。
這篇沒有示範「怎麼寫出完美涵蓋所有邊界情況的爬蟲測試」,因為這個系統目前確實還沒有做到。誠實承認「目前只有 happy path、邊界情況還沒涵蓋」,比宣稱這裡已經示範了完整的防禦,更貼近真實維護專案的樣子——測試覆蓋率的意義不只是「有沒有測試」,還包括「誠實知道現在測到哪裡、還缺什麼」,這份自知本身就是一種風險管理。
回想你手上專案裡任何一段跟外部系統整合的邏輯,測試涵蓋的是不是也只有「外部系統回應正常」這一種情況?如果外部系統哪天真的回應了一個你沒預期到的格式,你的程式碼會怎麼反應——這件事,你現在有把握回答嗎?
明天要看一支只用「症狀」驗證、不糾結內部實作細節的容錯測試——處理外部系統傳回的髒 XML 資料時,這種驗證方式為什麼反而更穩固。