使用 Swing、AWT 構建用戶界面時,測試向來是個難題:底層圖形框架複雜、表現層與業務邏輯耦合嚴重、缺乏直觀的自動測試框架。雖然前兩點是老生常談,但近年湧現的測試框架已大幅改善 GUI 測試體驗。本文介紹的 TestNG-Abbot,結合了 Abbot 的 GUI 組件隔離能力與 TestNG 的強大斷言與依賴管理,極大減輕了 GUI 測試的痛苦。
GUI 測試不等同於單元測試。驗證業務規則(如保存訂單寫入數據庫)屬於單元測試範疇;GUI 測試關注可見狀態變化——如點擊保存後,按鈕下方是否顯示成功提示。良好的設計下,兩類測試可並行編寫,甚至結合 DbUnit 實現端到端驗證。
示例 GUI 包含三個組件:JTextField(輸入單詞)、JButton(查詢)、JEditorPane(顯示釋義)。組件通過 setName() 設置邏輯名稱(如 findWord、wordValue、definition)。
public class WordFindGUITest {
private AbbotFixture fixture;
@BeforeMethod
private void initializeGUI() {
fixture = new AbbotFixture();
fixture.showWindow(new WordFind(), new Dimension(269, 184));
}
@AfterMethod
public void tearDownGUI() {
fixture.cleanUp();
}
}
@Test
public void assertDefinitionPresent() {
TextComponentFixture text1 = new TextComponentFixture(this.fixture, "wordValue");
text1.enterText("pugnacious");
ButtonFixture bfix = new ButtonFixture(this.fixture, "findWord");
bfix.click();
LabelFixture fix = new LabelFixture(this.fixture, "definition");
fix.shouldHaveThisText("Combative in nature; belligerent.");
}
空輸入:
@Test
public void assertNoWordPresentInvalidText() {
TextComponentFixture text1 = new TextComponentFixture(this.fixture, "wordValue");
text1.enterText("");
ButtonFixture bfix = new ButtonFixture(this.fixture, "findWord");
bfix.click();
LabelFixture fix = new LabelFixture(this.fixture, "definition");
fix.shouldHaveThisText("Please enter a valid word");
}
無效單詞:
@Test
public void assertInvalidWord() {
TextComponentFixture text1 = new TextComponentFixture(this.fixture, "wordValue");
text1.enterText("Ha77");
ButtonFixture bfix = new ButtonFixture(this.fixture, "findWord");
bfix.click();
LabelFixture fix = new LabelFixture(this.fixture, "definition");
fix.shouldHaveThisText("Word doesn't exist in dictionary");
}
TestNG-Abbot 雖是後起之秀,卻繼承了前輩優秀基因。它讓 GUI 組件隔離、驗證邏輯提取變得簡單直觀,無論正常流程還是邊界場景,只需知道組件邏輯名稱與用戶步驟,即可輕鬆編寫可維護的自動化測試。