在測試優先開發(Test-First Programming)中,開發者常面臨一個棘手問題:當程式高度依賴外部資源與函式庫時,自動化測試似乎難以實施,因為缺乏有效機制模擬程式與外部資源的連接。雖然純 Java 代碼難以測試此類程式,但基於組件的程式設計配合開發工具,卻能徹底解決這一困境。
這裡所指的「組件」並非 JavaBeans 那類執行期組件,而是指程式各單元處於分散狀態的編程模式。概念上,這些分散單元類似 Java 套件(package),但 Java 套件有嚴重侷限:套件間相互耦合。每個套件中的類別必須顯式引用所導入的套件,形成硬性連接,導致難以以提供相同功能的其他套件替換現有引用。此外,獨立開發團隊可能使用重複套件名,雖然 Sun 建議以反轉網域名作為前綴,但並非強制,衝突風險依然存在。
Jiazzi 是猶他大學計算機科學系開發的專案,完全兼容 JVM,且徹底解除組件間耦合。它允許程式設計師在現有 Java 代碼之上疊加、連接組件,無需修改 Java 語言或 JVM。Jiazzi 組件可視為 Java 套件的泛化,增加了外部連結與獨立編譯支援,從標準 Java 原始碼構建,無需語言擴展或特殊約定。
Jiazzi 引入單元作為組件連接的基本單位,類似樂高積木。單元分為兩類:
link 子句連接各單元實例。套件簽名類似類型,約束套件的結構(類別、方法簽名等)。導出套件的簽名可依賴導入套件的簽名,並支援參數化,進一步解耦簽名間依賴。
// 原子單元範例
atom app_view {
import toolkit: toolkit_s;
export view: view_s;
}
// 簽名定義
signature toolkit_s {
class Frame {
public Container getContentPane();
public Component getGlassPane();
}
class OptionPane {
public Object getDialog();
}
}
鏈接程式離線操作類別檔常量池,重命名隱藏方法避免衝突;亦可透過特定類別載入器線上鏈接,但需在載入器中進行型別檢查。
基於組件編程最大優勢在於大幅提升單元測試效率。測試時可使用特製的「仿製品」組件替換真實依賴,這些仿製品記錄被測組件行為,充當組件層面的記錄器。被測組件無法區分是連接真實組件還是仿製品,宛如「缸中之腦」。
例如,可定義 test_app 復合單元,將 app_view 與 test_toolkit 連接,後者導出相同簽名但僅含記錄行為的仿製物件。對比 Java 原生套件系統需修改所有原始檔重新編譯才能偽裝測試包,Jiazzi 實現了真正的自動化測試隔離。
Jiazzi 目前無法處理反射與 JNI,導致大量依賴這些機制的標準 Java API 無法直接轉為 Jiazzi 組件。但可採取折衷:將現有 API 打包為特殊單元(僅導出類別,導入仍硬連結 Java 套件系統),仍能為不使用反射/JNI 的自有套件提供強大測試機制。
Jiazzi 證明了基於組件的程式設計不僅利於代碼重用,更為測試驅動開發提供了強而有力的工具。雖然組件軟體市場尚未完全成熟,但這類工具已是面向測試編程的必要基礎設施。下一期將探討 Jam——一種支援 Mixin 的 Java 語言擴展,它將從類別層面解耦依賴關係,為測試帶來另一維度的突破。