可重復的系統測試

發表于:2008-04-03來源:作者:點擊數: 標簽:JWebUnit
在測試加入到 servlet 容器的 Web 應用程序時,編寫符合邏輯的可重復的測試尤其需要技巧。在 Andrew Glover 的提高代碼 質量 的這個續篇中,他介紹了 Cargo,這是一個以通用方式自動化容器管理的 開源 框架,有了這個框架,您可以隨時編寫符合邏輯的可重復的
在測試加入到 servlet 容器的 Web 應用程序時,編寫符合邏輯的可重復的測試尤其需要技巧。在 Andrew Glover 的提高代碼質量的這個續篇中,他介紹了 Cargo,這是一個以通用方式自動化容器管理的開源框架,有了這個框架,您可以隨時編寫符合邏輯的可重復的系統測試。

在本質上,像 JUnit 和 TestNG 一樣的測試框架方便了可重復性測試的創建。由于這些框架利用了簡單 Boolean 邏輯(以 assert 方法的形式)的可靠性,這使得無人為干預而運行測試成為可能。事實上,自動化是測試框架的主要優點之一 —— 我能夠編寫一個用于斷言具體行為的相當復雜的測試,且一旦這些行為有所改變,框架就會報告一個人人都能明白的錯誤。

利用成熟的測試框架會帶來框架 可重復性的優點,這是顯而易見的。但邏輯的 可重復性卻取決于您。例如,考慮創建用于驗證 Web 應用程序的可重復測試的情況,一些 JUnit 擴展框架(如 JWebUnit 和 HttpUnit)在協助自動化的 Web 測試方面非常好用。但是,使測試的 plumbing 可重復則是開發人員的任務,而這在部署 Web 應用程序資源時很難進行。

實際的 JWebUnit 測試的構造過程相當簡單,如清單 1 所示:


清單 1. 一個簡單的 JWebUnit 測試
package test.come.acme.widget.Web;import net.sourceforge.jwebunit.WebTester;import junit.framework.TestCase;public class WidgetCreationTest extends TestCase { private WebTester tester; protected void setUp() throws Exception { this.tester = new WebTester(); this.tester.getTestContext(). setBaseUrl("http://localhost:8080/widget/"); } public void testWidgetCreation() { this.tester.beginAt("/CreateWidget.html"); this.tester.setFormElement("widget-id", "893-44"); this.tester.setFormElement("part-num", "rt45-3"); this.tester.submit(); this.tester.assertTextPresent("893-44"); this.tester.assertTextPresent("suclearcase/" target="_blank" >ccessfully created."); }}

這個測試與一個 Web 應用程序通信,并試圖創建一個基于該交互的小部件。該測試隨后校驗此部件是否被成功創建。讀過本系列之前部分的讀者們也許會注意到該測試的一個微妙的可重復性問題。您注意到了嗎?如果這個測試用例連續 運行兩次會怎樣呢?

由這個小部件實例(即,widget-id)的驗證方面可以判斷出,可以安全地做出這樣的假設,即此應用程序中的數據庫約束很可能會阻止創建一個已經存在的額外的小部件。由于缺少了一個在運行另一個測試前刪除此測試用例的目標小部件的過程,如果再連續運行兩次,這個測試用例非常有可能會失敗。

幸運的是,如前面文章中所探討的那樣,有一個有助于數據庫-依賴性(database-dependent)測試用例可重復性的機制 —— 即 DbUnit。

使用 DbUnit

改進 清單 1 中的測試用例來使用 DbUnit 是非常簡單的。DbUnit 只需要一些插入數據庫的數據和一個相應的數據庫連接,如清單 2 所示:


清單 2. 用 DbUnit 進行的數據庫-依賴性測試
package test.come.acme.widget.Web;import java.io.File;import java.io.IOException;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import org.dbunit.database.DatabaseConnection;import org.dbunit.database.IDatabaseConnection;import org.dbunit.dataset.DataSetException;import org.dbunit.dataset.IDataSet;import org.dbunit.dataset.xml.FlatXmlDataSet;import org.dbunit.operation.DatabaseOperation;import net.sourceforge.jwebunit.WebTester;import junit.framework.TestCase;public class RepeatableWidgetCreationTest extends TestCase { private WebTester tester; protected void setUp() throws Exception { this.handleSetUpOperation(); this.tester = new WebTester(); this.tester.getTestContext(). setBaseUrl("http://localhost:8080/widget/"); } public void testWidgetCreation() { this.tester.beginAt("/CreateWord.html"); this.tester.setFormElement("widget-id", "893-44"); this.tester.setFormElement("part-num", "rt45-3"); this.tester.submit(); this.tester.assertTextPresent("893-44"); this.tester.assertTextPresent("successfully created."); } private void handleSetUpOperation() throws Exception{ final IDatabaseConnection conn = this.getConnection(); final IDataSet data = this.getDataSet(); try{ DatabaseOperation.CLEAN_INSERT.execute(conn, data); }finally{ conn.close(); } } private IDataSet getDataSet() throws IOException, DataSetException { return new FlatXmlDataSet(new File("test/conf/seed.xml")); } private IDatabaseConnection getConnection() throws ClassNotFoundException, SQLException { Class.forName("org.hsqldb.jdbcDriver"); final Connection jdbcConnection = DriverManager.getConnection("jdbc:hsqldb:hsql://127.0.0.1", "sa", ""); return new DatabaseConnection(jdbcConnection); }}

加入了 DbUnit,測試用例真的是可重復的了。在 handleSetUpOperation() 方法中,每當運行一個測試用例時,DbUnit 對數據執行一個 CLEAN_INSERT。此操作本質上將一個數據庫的數據清空并插入一個新的數據集,從而刪除任何之前創建的小部件。

再一次探討什么是 DbUnit?

DbUnit 是一個 JUnit 擴展,用于在運行測試時將數據庫放入一個已知狀態中。開發人員使用 XML 種子文件將特定數據插入到測試用例所依賴的數據庫中。因而,DbUnit 便利了依賴于一個或多個數據庫的測試用例的可重復性。

但那并不意味著已經結束了對測試用例可重復性這一話題的探討。事實上,一切才剛剛開始。

重復系統測試

我喜歡將 清單 1 和 清單 2 中定義的測試用例稱為系統測試。因為系統測試運行安裝完整的應用程序,如 Web 應用程序,它們通常包含一個 servlet 容器和一個相關聯的數據庫。這些測試的目的在于校驗那些設計為端對端操作的外部接口(如 Web 應用程序中的 Web 頁面)。

彈性優先級
作為總體規則,應在任何可能的時候避免測試用例繼承。許多 JUnit 擴展框架都提供特定的可繼承測試用例,以便利于測試一個特定的架構。然而由于 Java™ 平臺的單一繼承范例,使得從框架中繼承類的測試用例飽受缺乏彈性之苦。通常,這些相同的 JUnit 擴展框架提供了代理 API,這使得聯合各種不具有嚴格繼承結構的框架變得十分簡單。

由于設計它們的目的是為了測試功能完整的應用程序,因而系統測試趨向于增加運行次數而不是減少設置測試的總時間。例如,清單 1 和 清單 2 中展示的邏輯測試在運行前 需要下列步驟:

創建一個 war 文件,該文件包含所有相關 Web 內容,如 JSP 文件、servlet、第三方的 jar 文件、圖像等。

將此 war 文件部署到目標 Web 容器中。(如果該容器尚未啟動,啟動該容器。)

啟動任何相關的數據庫。(如果需要更新數據庫模式,在啟動前進行更新。)

現在,對于一個微不足道的小測試要做大量的輔助性工作!如果證明這個過程是耗時的,那么您認為這個測試會間隔多長時間運行一次呢?面對要使系統測試在邏輯上可重復(在一個連續的集成環境中)這一需求,這個步驟列表的確令人望而生畏。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97