「這個測試名稱都寫了 test_calculate_discount_with_member_level_and_coupon_returns_correct_price,還不夠詳細嗎?」
第一次看到 AI 生成這種落落長的測試名稱時,直覺反應是「至少它很認真」。但仔細讀完會發現一個問題:這串名稱幾乎是把方法簽章跟參數列表重新打一遍,卻沒有回答一個更關鍵的問題——這個測試到底在驗證哪一條業務規則?「詳細」跟「有資訊量」是兩件事,AI 很擅長做到前者,卻常常漏掉後者。
第一種:把實作細節搬進名稱。 AI 很容易把方法名稱、參數型別、甚至內部變數名稱原封不動塞進測試名稱裡,因為這是「看得到的資訊」,複製貼上最省力。結果是名稱很長,但讀者得到的資訊跟直接看程式碼签章差不多——沒有多告訴你「為什麼要測這個情境」。
第二種:命名過度通用,藏住了真正的情境。 另一個極端是 AI 寫出 test_discount_calculation 這種名稱,因為它把整個函式的功能濃縮成一句話,卻漏掉了「這次測試的具體條件是什麼」。如果同一個檔案裡有五個 test_discount_calculation_2、test_discount_calculation_3,讀者完全看不出這五個測試各自在驗證什麼差異。
這兩種失敗模式看似相反,根源卻是同一個:AI 在描述「這段程式碼做了什麼」,而不是描述「這個測試要證明什麼」。 前者是對程式碼的複述,後者才是測試命名真正該做的事。
一個有意義的測試名稱,應該讓讀者不用看內文就知道三件事:測試的是什麼情境、預期得到什麼結果、以及為什麼這個情境值得單獨測試。 常見的命名慣例是「情境_預期行為」或「方法名_情境_預期結果」,重點不在格式本身,而在於這個名稱有沒有把「為什麼要有這一條測試」講清楚。
用一組對照來看差異:
❌ 複述實作細節:
test_calculate_discount_with_member_level_and_coupon_returns_correct_price()
→ 幾乎是把方法簽章重講一遍,
讀者知道「呼叫了什麼」,但不知道「驗證的業務規則是什麼」
❌ 過度通用:
test_discount_calculation()
test_discount_calculation_2()
→ 同一個函式的五個測試都叫這個名字加編號,
完全看不出這五個測試分別驗證什麼差異情境
✅ 情境 + 預期行為:
test_vip_member_with_expired_coupon_gets_member_discount_only()
→ 讀者立刻知道:VIP 會員、優惠券已過期,
預期結果是「只套用會員折扣,優惠券不生效」——
這是一條具體的業務規則,也是這個測試存在的理由
測試名稱是寫給未來讀這份程式碼的人(可能是人、也可能是下一個接手的 AI)的說明書,不是寫給編譯器看的。 如果一個測試名稱只複述了程式碼在做什麼,讀者還是得打開內文才能知道「這條規則為什麼重要」;如果名稱把情境跟預期行為講清楚,測試報告本身就是一份活文件——CI 上一串失敗的測試名稱,應該能讓人不看程式碼就大致猜到「哪條業務規則被改壞了」。
AI 生成測試時,最容易取得的資訊就是眼前這段程式碼的簽章跟參數——這些資訊唾手可得,複製貼上零成本。但「這個情境為什麼值得單獨測試」這個問題,答案往往不在程式碼本身,而在需求脈絡裡:為什麼要特別測「VIP 會員 + 過期優惠券」這個組合?因為業務規則裡這是一個容易被搞混的邊界(該套用哪個折扣優先)。AI 沒有這層業務脈絡,只能退而求其次,複述它看得到的東西。
這也解釋了為什麼「讓 AI 幫忙產生測試骨架、由人補上情境脈絡」是比較實際的分工——AI 擅長把 Arrange-Act-Assert 的結構搭起來,但「這個情境代表什麼業務意義」這個命名該傳達的核心資訊,通常需要人補一句話才會到位。
打開你最近一次讓 AI 生成的測試檔案,隨便挑三個測試名稱:不看內文,你能不能光靠名稱猜出「這條測試在驗證哪一條業務規則」?如果猜不出來,那個名稱大概率只是複述了程式碼在做什麼。
明天要談另一個 AI 特別容易犯的錯:Mock 的濫用——AI 傾向把所有依賴都 mock 掉,隔離過頭之後,測試反而測不到真正的整合行為。