要使測試自動化,您需要一個測試框架。您可以自己開發或購買,也可以使用某些開放源代碼工具,例如 JUnit。我選擇 JUnit 出于以下幾個原因:
- 不需要編寫自己的框架。
- 它是開放源代碼,因此不需要購買框架。
- 開放源代碼社區中的其他開發者會使用它,因此可以找到許多示例。
- 它可以讓我將測試代碼與產品代碼分開。
- 它易于集成到我的構建過程中。
測試布局
圖 1 顯示了使用樣本 TestSuite 的 JUnit TestSuite 布局。每個測試都由若干單獨的測試案例構成。每個測試案例都是一個單獨的類,它擴展了 TestClass 類并包含了我的測試代碼,即那些曾在 main()
中出現的代碼。在該例中,我向 TestSuite 添加了兩個測試:一個是 SkeletonTest,我將它用作所有新類和 HelloWorld 類的起點。
圖 1. TestSuite 布局

測試類 HelloWorldTest.java
按照約定,測試類的名稱中包含我所測試的類的名稱,但將 Test 附加到結尾。在本例中,我們的測試類是 HelloWorldTest.java
。我復制了 SkeletonTest 中的代碼,并添加了 testSayHello()
來測試 sayHello()
。請注意 HelloWorldTest 擴展了 TestCase。JUnit 框架提供了 assert
和 assertEquals
方法,我們可以使用這些方法來進行驗證。 HelloWorldTest.java
顯示在清單 2 中。
清單 2. HelloWorldTest.java
|
testSayHello()
看上去和 HelloWorld.java
中原來的 main 方法類似,但有一個主要的不同之處。它不是執行 System.out.println
并顯示結果,而是添加了一個 assertEquals()
方法。如果兩個值不同, assertEquals
將打印出兩個輸入的值。您可能已經注意到這個方法不起作用!HelloWorld 中的 sayHello()
方法不返回字符串。如果我先寫過測試,就會捕捉到這一點。我將 "Hello World" 字符串與輸出流聯結起來。這樣,按照清單 3 中顯示的那樣重寫了 HelloWorld,去掉 main()
,并更改了 sayHello()
的返回類型。
清單 3. Hello world 測試案例。
|
如果我保留了 main()
并修改了聯系,代碼看上去如下:
|
新的 main()
與我測試程序中的 testSayHello()
非常相似。是的,它看上去不象是一個現實世界中的問題(這是人為示例的問題),但它說明了問題。在單獨的應用程序中編寫 main()
可以改進您的設計,同時幫助您設計測試?,F在我們已經創建了一個測試類,讓我們使用 Ant 來將它集成到構建中。
![]() ![]() |
![]()
|
Jakarta Project 將 Ant 工具說成“不帶 make 缺點的 make”。Ant 正在成為開放源代碼世界中實際上的標準。原因很簡單:Ant 是使用 Java 語言編寫的,這種語言可以讓構建過程在多種平臺上使用。這種特性簡化了在不同 OS 平臺之間的程序員的合作,而合作是開放源代碼社區的一種需要。您可以在自己選擇的平臺上進行開發 和構建。Ant 的特性包括:
- 類可擴展性 Java 類可用于擴展構建特性,而不必使用基于 shell 的命令。
- 開放源代碼 因為 Ant 是開放源代碼,因此類擴展示例很充足。我發現通過示例來學習非常棒。
- XML 可配置 Ant 不僅是基于 Java 的,它還使用 XML 文件配置構建過程。假設構建實際上是分層的,那么使用 XML 描述 make 過程就是其邏輯層。另外,如果您了解 XML,要學習如何配置構建就更簡單一些。
圖 2 簡要介紹了一個配置文件。配置文件由目標樹構成。每個目標都包含了要執行的任務,其中任務就是可以執行的代碼。在本例中, mkdir是目標 compile的任務。 mkdir是建立在 Ant 中的一個任務,用于創建目錄。 Ant 帶有一套健全的內置任務。您也可以通過擴展 Ant 任務類來添加自己的功能。
每個目標都有唯一的名稱和可選的相關性。目標相關性需要在執行目標任務列表之前執行。例如圖 2 所示,在執行 compile 目標中的任務之前需要先運行 JUNIT 目標。這種類型的配置可以讓您在一個配置中有多個樹。
圖 2. Ant XML 構建圖

與經典 make 實用程序的相似性是非常顯著的。這是理所當然的,因為 make 就是 make。但也要記住有一些差異:通過 Java 實現的跨平臺和可擴展性,通過 XML 實現的可配置,還有開放源代碼。
下載和安裝 Ant
首先下載 Ant(請參閱 參考資料 )。將 Ant 解壓縮到 tools 目錄,再將 Ant bin
目錄添加到路徑中。(在我的機器上是 e:"tools"ant"bin
。)設置 ANT_HOME 環境變量。在 NT 中,這意味著進入系統屬性,然后以帶有值的變量形式添加 ANT_HOME。ANT_HOME 應該設置為 Ant 根目錄,即包含 bin
和 lib
目錄的目錄。(對我來說,是 e:"tools"ant
。)確保 JAVA_HOME 環境變量設置為安裝了 JDK 的目錄。Ant 文檔有關于安裝的詳細信息。
下載和安裝 JUnit
下載 JUnit 3.2(請參閱 參考資料 )。解開 junit.zip
,并將 junit.jar
添加到 CLASSPATH。如果將 junit.zip
解包到類路徑中,可以通過運行以下命令來測試安裝: java junit.textui.TestRunner junit.samples.AllTests
定義目錄結構
在開始我們的構建和測試過程之前,需要一個項目布局。圖 3 顯示了我的樣本項目的布局。下面描述了布局的目錄結構:
build
-- 類文件的臨時構建位置。構建過程將創建這個目錄。src
-- 源代碼的位置。Src
被分為test
文件夾和main
文件夾,前者用于所有的測試代碼,而后者包含可交付的代碼。將測試代碼與主要代碼分離提供了幾點特性。首先,使主要代碼中的混亂減少。其次,它允許包對 齊。我就熱衷與將類和與其相關的包放置在一起。測試就應該和測試在一起。它還有助于分發過程,因為你不可能打算將單元測試分發給客戶。
在實際中,我們有多個目錄,例如 distribution
和 documentation
。我們還會在 main
下有多個用于包的目錄,例如 com.company.util
。
因為目錄結構經常變動,所以在 build.xml
中有這些變動的全局字符串常數是很重要的。
圖 3. 項目布局圖

Ant 構建配置文件示例
下一步,我們要創建配置文件。清單 4 顯示了一個 Ant 構建文件示例。構建文件中的關鍵就是名為 runtests 的目標。這個目標進行分支判斷并運行外部程序,其中外部程序是前面已安裝的 junit.textui.TestRunner
。我們指定要使用語句 test.com.company.AllJUnitTests
來運行哪個測試套件。
清單 4. 構建文件示例
|
運行 Ant 構建示例
開發過程中的下一步是運行將創建和測試 HelloWorld 類的構建。清單 5 顯示了構建的結果,其中包括了各個目標部分。最酷的那部分是 runtests 輸出語句:它告訴我們整個測試套件都正確運行了。
我在圖 4 和圖 5 中顯示了 JUnit GUI,其中所要做的就是將 runtest 目標從 junit.textui.TestRunner
改為 junit.ui.TestRunner
。當您使用 JUnit 的 GUI 部分時,您必須選擇退出按鈕來繼續構建過程。如果使用 Junit GUI
構建包,那么它將更難與大型的構建過程相集成。另外,文本輸出也與構建過程更一致,并可以定向輸出到一個用于主構建記錄的文本文件。這對于每天晚上都要進
行的構建非常合適。
清單 5. 構建輸出示例
|
圖 4. JUnit GUI 測試成功

圖 5. JUnit GUI 測試失敗

![]() ![]() |
![]()
|
讓我們搞點破壞,然后看看會發生什么事。夜深了,我們決定把 "Hello World" 變成一個靜態字符串。在更改期間,我們 不小心打錯了字母,將 "o" 變成了 "0",如清單 6 所示。
清單 6. Hello world 類更改
|
在建包時,我們看到了錯誤。清單 7 顯示了 runtest 中的錯誤。它顯示了失敗的測試類和測試方法,并說明了為什么會失敗。我們返回到代碼中,改正錯誤后離開。
清單 7. 構建錯誤示例
|