搶先一步
VMware 提供培訓和認證,以加速您的進展。
瞭解更多過去幾個月,我一直與各種客戶合作,參與使用 Google Web Toolkit [GWT] 的專案。我主要喜歡 GWT 是因為它的 Java 到 javascript 編譯器。這是讓凡人 Java 開發人員無需學習新語言即可創建 RIA 的關鍵。
我一直以來都是測試驅動開發的愛好者,但起初讓我失望的是,TDD 和 GWT 似乎無法協同運作。
測試 GWT 程式碼有點問題。問題的核心在於 GWT 程式碼在執行前會編譯為 javascript。在許多情況下,會使用 GWT.create() 語句來連結到動態綁定機制。在正常的 Java 環境中執行此語句會導致例外。
即使您使用像 EasyMock 這樣的模擬程式庫來模擬罪魁禍首,如果它是從建構子觸發的,您仍然很可能遇到問題。為所有 widget 建立介面太過繁瑣,即使您這樣做了,您也將無法測試包含 GWT.create() 的特定類別。
GWT 在 GWTTestCase 中為此問題提供了解決方案,但這個類別本身也存在不少問題。僅舉幾個例子
當您進行測試驅動開發時,您需要能夠編寫至少具有以下屬性的測試
那麼,我們該怎麼做才能防止我們的程式碼因缺乏測試而變成義大利麵條,同時將那些緩慢的 GWTTestCase 保持在最低限度? MVC 來救援
MVC 是一種歷史悠久的模式。它有很多應用,其中一些應用與原始 MVC 模式幾乎沒有共同之處,除了名稱之外,但我想要指出的總體方向最好由 Martin Fowler 以 Humble View 的名稱概括。
我更簡短的總結是:視圖通常很難測試,因此它們應該盡可能少地了解和執行操作。在 GWT 中,視圖與 Widget 同義。現在這裡有一個小小的陷阱:任何在客戶端運行的東西都歸 Widget 所有。大多數 GWT 程式碼幾乎將所有邏輯都放在 widget 中,因此大多數使用 GWT 的開發人員都會擴展 widget 並僅添加一些更多邏輯。
我的建議很簡單:不要去那裡。類型安全很好,可以獲得 IDE 支援,但它無助於防止您編寫糟糕的程式碼。因此,如果您不進行單元測試,您的程式碼最終會變得一團糟。
如果您不走將邏輯放入視圖(Widget 子類別)的路徑,您將需要另一個地方來放置它。這就是 Controller 的用武之地。回到我之前提到的陷阱,我們需要從 Widget 或 EntryPoint 啟動控制器。實際上沒有辦法避免這一點,所以讓我們這樣做,看看它有多糟糕
public class NoteEditor extends Composite {
public NoteEditor() {
//do the dependency injection stuff
NoteModel noteModel = new NoteModel();
NoteEditorController controller =
new NoteEditorController(noteModel, NoteService.App.getInstance(), new AlertCallback());
//...
}
}
如您所見,我在這裡從程式碼中完成了一些依賴注入,因為我們在客戶端還沒有 Spring。我說還沒有,因為我們稍後可以使用 GWToolbox 或 Rocket 來實現。該服務使用 GWT.create() 來啟動,而 AlertCallback 用於將控制器與 Window 解耦,以處理偶爾的警示。我認為這還不算太糟,我可以安心地睡覺,而無需為此程式碼編寫測試。問題還沒有完全結束,因為我們想要在視圖中使用的任何元素(按鈕、標籤等)都需要在視圖中實例化,然後向控制器註冊
controller.registerDetailViewSelector(new DeckPanelSelector(detailView));
detailView.addStyleName("detailPanel");
main.add(detailView, DockPanel.CENTER);
//some buttons at the bottom of the screen
buttonPanel.add((Widget)controller.registerClearButton(new Button("Clear")));
buttonPanel.add((Widget)controller.registerLoadButton(new Button("Load existing Note")));
控制器接受介面 (SourcesClickEvents) 下的按鈕,這作為一個額外的好處,允許我們用一些外觀不同的 Widget 替換按鈕,而無需更改我們的控制器。這裡沒有什麼新鮮事,這正是 MVC 所關注的關注點分離。老實說,我通常更願意編寫一個測試來檢查註冊是否已正確發生,但這是在沒有 GWTTesCase 的情況下無法完成的。現在是時候讓我們的 IDE 為我們建立控制器 + 方法,並編寫測試,以便我們可以實作邏輯。例如,載入按鈕的測試看起來像這樣
public void testLoadButtonPressed_success() throws Exception {
final Foo expectedFoo = new Foo("expected");
fooServiceMock.loadFoo(isA(String.class), isA(AsyncCallback.class));
expectLastCall().andAnswer(new IAnswer() {
public Object answer() throws Throwable {
((AsyncCallback) getCurrentArguments()[1]).onSuccess(expectedFoo);
return null;
}
});
fooModelMock.setFoo(expectedFoo);
replay(allMocks);
loadButton.fireClick();
verify(allMocks);
}
我們開始吧!我附加了一個快速範例來展示這個想法。您可以將其用作實驗的起點。
2008-10 更新:範例的來源已過時。一般建議仍然適用。
總結一下 GWT 風格 MVC 模式的快速草圖。當然,您可以選擇自己的風格,只要您將邏輯保存在可測試的類別中即可。