第一步是为每个 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
。