首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Selenium + TestNG 程式化驗收測試實戰:結合 DbUnit 與 Cargo 實現可重複的端到端自動化

     編輯:Java 相關知識

前言

Selenium 以真實瀏覽器驅動 Web 測試,區別於模擬 HTTP 請求的工具。結合 TestNG 強大的參數化、依賴管理、失敗重跑能力,再整合 DbUnit (資料庫狀態管理) 與 Cargo (容器生命週期自動化),即可構建完全自動化、可重複執行、跨瀏覽器的驗收測試體系。

架構總覽

[Ant/Maven/CI] → [Cargo: 啟動容器 + 部署 WAR] → [Selenium Server 啟動] 
    → [TestNG: 執行 Selenium 測試套件 (Firefox/IE/Chrome)] 
    → [DbUnit: 每測試群組前 CLEAN_INSERT 種子資料]
    → [Cargo: 停止容器] → [Selenium Server 關閉] → [測試報告]

Selenium 程式化 API 基礎

啟動 Selenium Server 並驅動瀏覽器

Selenium driver = new DefaultSelenium(
    "localhost",                    // Selenium Server 位址
    SeleniumServer.getDefaultPort(), // 4444
    "*firefox",                     // 瀏覽器啟動參數
    "https://localhost:8080/app/"    // 被測應用基礎 URL
);
driver.start();
// ... 執行測試步驟 ...
driver.stop();

核心操作 API

方法用途範例
open(url)導航至頁面driver.open("/CreateWidget.html")
type(locator, value)輸入框填值driver.type("widget", "book-01")
click(locator)點擊元素driver.click("submit")
select(locator, option)下拉選單選值driver.select("type", "book")
waitForPageToLoad(timeoutMs)等待頁面載入driver.waitForPageToLoad("10000")
getText(locator)取得元素文字driver.getText("success")
getTitle()取得頁面標題driver.getTitle()

定位器支援:id=xxx、name=xxx、xpath=//div[@class='foo']、css=.bar、dom=...。

TestNG 驅動 Selenium 測試結構

彈性 Selenium Fixture (參數化瀏覽器、Server、App URL)

public class CreateWidgetUATest {
    private Selenium driver;

    @Parameters({"selen-svr-addr", "brwsr-path", "aut-addr"})
    @BeforeClass
    private void init(String selenSrvrAddr, String bpath, String appPath) throws Exception {
        driver = new DefaultSelenium(selenSrvrAddr, SeleniumServer.getDefaultPort(), bpath, appPath);
        driver.start();
    }

    @Parameters({"aut-addr"})
    @Test
    public void verifyCreate(String appPath) throws Exception {
        driver.open(appPath + "/CreateWidget.html");
        driver.type("widget", "book-01");
        driver.select("type", "book");
        driver.type("definition", "book widget type book");
        driver.click("submit");
        driver.waitForPageToLoad("10000");
        assertEquals(driver.getText("success"), "The widget book-01 was successfully created.");
    }

    @Parameters({"aut-addr"})
    @Test
    public void verifyCreationError(String appPath) throws Exception {
        driver.open(appPath + "/CreateWidget.html");
        driver.type("widget", "book-02");
        driver.select("type", "book");
        driver.type("definition", "");  // 故意留空觸發驗證錯誤
        driver.click("submit");
        driver.waitForPageToLoad("10000");
        assertEquals(driver.getText("failure"), "There was an error in creating the widget.");
    }

    @AfterClass
    private void stop() throws Exception {
        driver.stop();
    }
}

testng.xml - 參數化與多瀏覽器並行

<suite name="User Acceptance Tests" verbose="1" parallel="tests" thread-count="2">
    <!-- 共用參數:DbUnit、Selenium Server、App URL -->
    <parameter name="seed-path" value="test/conf/gt15-seed.xml"/>
    <parameter name="db-driver" value="org.hsqldb.jdbcDriver"/>
    <parameter name="db-url" value="jdbc:hsqldb:hsql://127.0.0.1"/>
    <parameter name="db-user" value="sa"/>
    <parameter name="db-psswrd" value=""/>
    <parameter name="selen-svr-addr" value="localhost"/>
    <parameter name="aut-addr" value="https://localhost:8080/gt15/"/>

    <test name="GT15 CRUDs - Firefox">
        <parameter name="brwsr-path" value="*firefox"/>
        <packages>
            <package name="test.com.acme.gt15.Web.selenium"/>
            <package name="test.com.acme.gt15.Web.selenium.fixtures"/>
        </packages>
    </test>

    <test name="GT15 CRUDs - IE">
        <parameter name="brwsr-path" value="*iexplore"/>
        <packages>
            <package name="test.com.acme.gt15.Web.selenium"/>
            <package name="test.com.acme.gt15.Web.selenium.fixtures"/>
        </packages>
    </test>
</suite>

關鍵特性:

  • parallel="tests" thread-count="2":Firefox 與 IE 並行執行
  • 參數作用域隔離:Suite 級共用參數,Test 級覆寫瀏覽器參數
  • @BeforeTest / @AfterTest:測試群組級 Fixture (DbUnit 種子資料)

DbUnit:測試群組級資料庫狀態管理

DatabaseFixture - @BeforeTest 種子資料裝載

public class DatabaseFixture {
    @Parameters({"seed-path", "db-driver", "db-url", "db-user", "db-psswrd"})
    @BeforeTest
    public void seedDatabase(String seedpath, String driver, String url, String user, String pssword) throws Exception {
        IDatabaseConnection conn = getConnection(driver, url, user, pssword);
        IDataSet data = getDataSet(seedpath);
        try {
            DatabaseOperation.CLEAN_INSERT.execute(conn, data);  // 刪除舊資料 → 插入新資料
        } finally {
            conn.close();
        }
    }

    private IDataSet getDataSet(String path) throws IOException, DataSetException {
        return new FlatXmlDataSet(new File(path));
    }

    private IDatabaseConnection getConnection(String driver, String url, String user, String pssword) throws Exception {
        Class.forName(driver);
        Connection jdbcConnection = DriverManager.getConnection(url, user, pssword);
        return new DatabaseConnection(jdbcConnection);
    }
}

CLEAN_INSERT 確保每個測試群組 () 都從乾淨、已知狀態開始,支援測試重複執行不受資料殘留影響。

Cargo:容器生命週期自動化 (Ant 整合範例)

Ant Target 串聯 Cargo → Selenium → TestNG

<target name="ua-test" depends="compile-tests,war">
    <taskdef resource="cargo.tasks">
        <classpath>
            <pathelement location="${libdir}/${cargo-jar}"/>
            <pathelement location="${libdir}/${cargo-ant-jar}"/>
        </classpath>
    </taskdef>

    <!-- 1. Cargo 啟動 Tomcat 並部署 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>

    <!-- 2. 啟動 Selenium Server 並執行測試 -->
    <antcall target="_start-selenium"/>

    <!-- 3. 測試完成後停止 Tomcat -->
    <cargo containerId="tomcat5x" action="stop" refid="${tomcat-refid}"/>
</target>

<target name="_start-selenium">
    <java jar="${libdir}/${selenium-srvr-jar}" fork="true" spawn="true"/>
    <antcall target="_run-ua-tests"/>
    <get dest="${testreportdir}/results.txt" 
         src="${selenium-srvr-loc}/selenium-server/driver/?cmd=shutDown"/>
</target>

<target name="_run-ua-tests">
    <taskdef classpathref="build.classpath" resource="testngtasks"/>
    <testng outputDir="${testreportdir}" classpath="${testclassesdir};${classesdir}" haltonfailure="true">
        <xmlfileset dir="./test/conf" includes="testng.xml"/>
        <classpath><path refid="build.classpath"/></classpath>
    </testng>
</target>

Cargo 優勢:同一 API 支援 Tomcat/JBoss/Jetty/GlassFish/Resin,自動下載安裝指定版本,跳過已存在版本。

現代化遷移建議 (Selenium 4 / TestNG 7+ / Maven / GitHub Actions)

舊技術現代替代遷移重點
Selenium RC (DefaultSelenium)Selenium 4 WebDriverWebDriver API、W3C 標準、原生瀏覽器驅動、無需 Selenium Server (可選 Grid)
Ant 建置腳本Maven / Gradle依賴管理、標準目錄結構、插件生態豐富
Cargo Ant TaskCargo Maven Plugin / TestcontainersTestcontainers 以 Docker 管理容器,更輕量、隔離性更好
DbUnit XML 種子檔Testcontainers + Flyway/Liquibase / @Sql資料庫遷移工具管理結構,測試資料用 @Sql 或程式化建構
TestNG XML SuiteTestNG 7+ / JUnit 5JUnit 5 擴展模型強大,TestNG 仍優於參數化/依賴/並行控制
IE/Firefox 參數化Chrome/Edge/Firefox/Safari + Selenium Grid / Cloud (Sauce Labs/BrowserStack)跨瀏覽器雲端測試平台

總結

Selenium + TestNG + DbUnit + Cargo 組合展示了端到端驗收測試自動化的完整樣貌:

  1. 真實瀏覽器驗證:Selenium 捕捉 JS/CSS/排版等單元測試無法發現的問題
  2. 參數化靈活:TestNG 參數化支援多瀏覽器、多環境、多資料集
  3. 狀態可控:DbUnit 確保資料庫乾淨狀態,Cargo 確保容器乾淨部署
  4. 完全自動化:一鍵觸發 (Ant/CI),無人值守執行,產出報表

雖技術棧已演進,但架構思維 (基礎設施即代碼、測試隔離、參數化、可重複性) 永不過時。現代專案建議採用 WebDriver + Testcontainers + JUnit 5/TestNG + GitHub Actions/GitLab CI 重構同樣架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved