JUnit、TestNG 等測試框架的核心價值在於讓測試具備「可重複性」。它們利用簡單的 Boolean 邏輯(斷言方法),使測試能在無人干預下自動運行並產出清晰可讀的結果。自動化正是測試框架最大的優勢:開發者只需編寫一次斷言業務行為的測試,當行為發生變化時,框架即刻回報錯誤。
然而,框架僅解決了「執行層面」的可重複。邏輯層面的可重複——即測試在連續執行時不因環境殘留而失敗——則全賴開發者自行把控。以 Web 應用測試為例,JWebUnit、HttpUnit 等擴展雖能自動化 HTTP 交互,但測試所需的資料庫狀態、容器部署等「管道工程」若無妥善處理,測試便難以真正重複執行。
觀察以下 JWebUnit 測試片段:
public void testWidgetCreation() {
tester.beginAt("/CreateWidget.html");
tester.setFormElement("widget-id", "893-44");
tester.setFormElement("part-num", "rt45-3");
tester.submit();
tester.assertTextPresent("893-44");
tester.assertTextPresent("successfully created.");
}
此測試嘗試建立 widget 並驗證成功訊息。若連續執行兩次,次將因資料庫主鍵衝突而失敗——首次運行已插入資料,次運行違反唯一性約束。缺少「測試前清理、測試後復原」的機制,導致測試不可重複。
DbUnit 正是為解決此問題而生。它是 JUnit 擴展,透過 XML 種子檔案在測試執行前將資料庫置於已知狀態。改寫後的測試在 setUp() 中呼叫 DatabaseOperation.CLEAN_INSERT,先清空相關表再載入種子資料,確保每次測試都從乾淨的基線開始:
private void handleSetUpOperation() throws Exception {
IDatabaseConnection conn = getConnection();
IDataSet data = getDataSet();
try {
DatabaseOperation.CLEAN_INSERT.execute(conn, data);
} finally {
conn.close();
}
}
至此,單元測試層面的可重複性已獲保障。但系統測試還涉及容器啟動、應用部署等更龐大的基礎設施問題。
系統測試需驗證端到端流程,通常涉及:打包 WAR、部署至 Servlet 容器、啟動資料庫、更新 Schema。這些步驟耗時且繁瑣,若無自動化,開發者極少頻繁執行系統測試,持續整合更無從談起。
Cargo 是開源專案,提供統一 API 管理各類容器(Tomcat、Jetty、JBoss 等),支援下載、安裝、啟動、停止、部署 WAR/EAR。同一套 Ant/Maven 腳本即可針對不同容器運作,極大降低了自動化門檻。
以下 Ant 片段示範如何用 Cargo 下載並啟動 Tomcat 5.0.28、部署 WAR,測試結束後自動停止容器:
<target name="system-test" depends="init,compile-tests,war">
<cargo containerId="tomcat5x" action="start" wait="false" id="${tomcat-refid}">
<zipurlinstaller installurl="${tomcat-installer-url}"/>
<configuration type="standalone" home="${tomcatdir}">
<property name="cargo.remote.username" value="admin"/>
<property name="cargo.remote.password" value=""/>
<deployable type="war" file="${wardir}/${warfile}"/>
</configuration>
</cargo>
<antcall target="_run-system-tests"/>
<cargo containerId="tomcat5x" action="stop" refid="${tomcat-refid}"/>
</target>
_run-system-tests 目標則透過 JUnit 批次執行 test/system 目錄下的系統測試。整個流程無假設容器預裝、無假設固定安裝路徑,真正實現了「隨時、隨地、可重複」的系統測試。
引入 Cargo 後,Ant 建置輸出顯示容器自動下載、啟動、部署、測試通過、關閉,全程無人值守。Cargo 亦支援 Maven 及 Java API,測試框架不限於 JUnit,TestNG 同樣適用。核心啟示在於:將容器管理外包給 Cargo,開發者得以專注於測試邏輯本身,構建真正可重複、可信賴的系統測試體系。