第一步是為每個 UI 組件創建訪問器方法,如清單 2 所示。按照該方式,我可以在需要時獲取它們。
清單 2. 向 UI 組件添加訪問器方法使其可用
public class WordModule implements EntryPoint { private Label label; private Button button; private TextBox textBox; private Label outputLabel; protected Button getButton() { if (this.button == null) { this.button = new Button("Submit"); } return this.button; } protected Label getLabel() { if (this.label == null) { this.label = new Label("Word: "); } return this.label; } protected Label getOutputLabel() { if (this.outputLabel == null) { this.outputLabel = new Label(); } return this.outputLabel; } protected TextBox getTextBox() { if (this.textBox == null) { this.textBox = new TextBox(); this.textBox.setVisibleLength(20); } return this.textBox; }} |
現在我實現了對所有與 UI 相關的組件的編程式訪問(假設所有需要進行訪問的類都在同一個包內)。以后我可能需要使用其中一種訪問進行驗證。我現在希望限制 使用訪問器,如我已經指出的,這是因為 GWT 并非設計用來進行交互測試。所以,我不是真的要試圖測試某個按鈕實例是否被單擊,而是要測試 GWT 模塊是否會對給定的單詞調用服務器端代碼,并且服務器端會返回一個有效定義。方法為將 onModuleLoad()
方法的定義獲取邏輯推入(不是故意用雙關語。┮粋可測試方法中,如清單 3 所示:
清單 3. 重構的 onModuleLoad 方法委托給更易于測試的方法
public void onModuleLoad() { HorizontalPanel inputPanel = new HorizontalPanel(); inputPanel.setStyleName("disco-input-panel"); inputPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); Label lbl = this.getLabel(); inputPanel.add(lbl); TextBox txBox = this.getTextBox(); inputPanel.add(txBox); Button btn = this.getButton(); btn.addClickListener(new ClickListener() { public void onClick(Widget sender) { submitWord(); } }); inputPanel.add(btn); inputPanel.setCellVerticalAlignment(btn, HasVerticalAlignment.ALIGN_BOTTOM); if(RootPanel.get("input-container") != null) { RootPanel.get("input-container").add(inputPanel); } Label output = this.getOutputLabel(); if(RootPanel.get("output-container") != null) { RootPanel.get("output-container").add(output); }} |
如清單 3 所示,我已經把 onModuleLoad()
的定義獲取邏輯委托給 submitWord
方法,如清單 4 定義:
清單 4. 我的 Ajax 應用程序的實質!
protected void submitWord() { String word = this.getTextBox().getText().trim(); this.getDefinition(word);}protected void getDefinition(String word) { WordServiceAsync instance = WordService.Util.getInstance(); try { instance.getDefinition(word, new AsyncCallback() { public void onFailure(Throwable error) { Window.alert("Error occurred:" + error.toString()); } public void onSuccess(Object retValue) { getOutputLabel().setText(retValue.toString()); } }); }catch(Exception e) { e.printStackTrace(); }} |
submitWord()
方法又委托給 getDefinition()
方法,我可以用 JUnit 測試它。getDefinition()
方法從邏輯上獨立于特定于 UI 的代碼(對于絕大部分而言),并且可以在沒有單擊按鈕的情況下得到調用。另一方面,與異步應用程序有關的狀態問題和 Java 語言的語義規則也規定了我不能在測試中完全 避免與 UI 相關的交互。仔細查看清單 4 中的代碼,您能夠發現激活異步回調的 getDefinition()
方法操縱了某些 UI 組件 —— 一個錯誤警告窗口以及一個 Label
實例。
Label
實例的句柄,斷言其文本是否是給定單詞的定義,從而驗證應用程序的功能。在用 GWTTestCase
測試時,最好不要 嘗試手工強制改變組件狀態,而應該讓 GWT 完成這些工作。舉例而言,在清單 4 中,我想驗證對某個給定單詞返回了其正確定義并放入一個輸出 Label
中。無需操作 UI 組件來設置這個單詞;我只要直接調用 getDefinition
方法,然后斷言 Label
具有對應定義。
GWTTestCase
。
![]() |