章節概述#
本章是 Part 2 的回顧與總結。作者反思了自行實作 xUnit 的價值、xUnit 在實際使用中的一些重要區分(assertion failure vs. error),以及如何將 xUnit 擴展到不同語言和場景。
自行實作 xUnit 的理由#
xUnit 已被移植到超過 30 種程式語言,你使用的語言很可能已經有現成的實作。但作者認為仍有兩個理由值得自己動手做一次:
- 掌握感(Mastery) — xUnit 的精神是簡潔。Martin Fowler 曾說:「軟體工程史上,從未有如此少的程式碼對如此多的人產生如此大的影響。」有些實作已經變得過於複雜,自己寫一遍能讓你對工具有完全的掌控。
- 探索語言(Exploration) — 當作者面對一種新的程式語言時,他會實作 xUnit。寫完前八到十個測試時,他已經探索了日常開發會用到的大部分語言設施。
技巧: 如果你正在學習一門新語言,嘗試用 TDD 的方式實作 xUnit。這是一個絕佳的練習,能同時熟悉語言特性和 TDD 方法論。
Failure vs. Error 的區分#
當你開始使用 xUnit,會發現 assertion failure 和其他類型的錯誤之間有很大的差異:assertion failure 通常需要更長的除錯時間。
因此,大多數 xUnit 實作會區分:
- Failure — assertion 失敗,代表預期與實際結果不符
- Error — 測試執行過程中的其他異常(如 NullPointerException)
GUI 介面通常會分開呈現,錯誤(error)往往排在前面顯示。
Test 介面與擴展性#
JUnit 宣告了一個簡單的 Test 介面,TestCase 和 TestSuite 都實作它:
public interface Test {
public abstract int countTestCases();
public abstract void run(TestResult result);
}如果你希望 JUnit 工具能執行你的測試,你只需實作這個介面即可。
補充: 使用動態型別(optimistic typing)的語言甚至不需要宣告介面——只要實作對應的操作就好。例如,你可以寫一個測試腳本語言,讓
Script實作countTestCases()回傳 1、run()在失敗時通知TestResult,就能和一般的TestCase一起執行。
本章小結#
Part 2 的核心訊息:
- Part 2 展示的測試案例序列(test cases)比實作細節更重要——如果你能支援類似的測試案例,就能寫出隔離且可組合的測試
- 自行實作 xUnit 能帶來掌控感和對語言的深入探索
- 實務上要注意 failure 與 error 的區分,這會影響除錯效率
- xUnit 的設計核心是一個簡單的
Test介面,使得框架具有高度擴展性