2012-12-06 50 views
8

我正在使用GWTP,添加了一個合同層來抽象Presenter和View之間的知識,我對GWTP的結果非常滿意。 我正在用Mockito測試我的演示者。使用異步調用測試GWTP演示者

但隨着時間的推移,我發現很難保持一個乾淨的主持人的測試。 我有一些重構的東西可以改善,但我還是不滿意。

我發現下面是問題的心臟: 我的主持人需要經常異步調用,或通常調用對象的方法有回調繼續我的演講流(它們通常是嵌套)。

例如:

this.populationManager.populate(new PopulationCallback() 
    { 
    public void onPopulate() 
    { 
     doSomeStufWithTheView(populationManager.get()); 
    } 
    }); 

在我的測試中,我最終驗證嘲笑PopulationManager對象的人口()調用。然後在doSomeStufWithTheView()方法上創建另一個測試。但是我很快就發現它是糟糕的設計:任何更改或重構都會導致我的測試中斷,並迫使我從其他人開始創建,即使演示者功能沒有改變! 另外我沒有測試回調是否是我想要的。

所以我試圖用的Mockito doAnswer方法不破我的演示測試流程:

doAnswer(new Answer(){ 
    public Object answer(InvocationOnMock invocation) throws Throwable 
    { 
     Object[] args = invocation.getArguments(); 
     ((PopulationCallback)args[0]).onPopulate(); 
     return null; 
    } 
}).when(this.populationManager).populate(any(PopulationCallback.class)); 

我分解它的代碼是更簡潔(和國內較少依賴於ARG位置):

doAnswer(new PopulationCallbackAnswer()) 
    .when(this.populationManager).populate(any(PopulationCallback.class)); 

因此而嘲笑populationManager,我仍然可以測試我的演講的流動,基本上都是這樣的:

@Test 
public void testSomeStuffAppends() 
{ 
    // Given 
    doAnswer(new PopulationCallbackAnswer()) 
    .when(this.populationManager).populate(any(PopulationCallback.class)); 

    // When 
    this.myPresenter.onReset(); 

    // Then 
    verify(populationManager).populate(any(PopulationCallback.class)); // That was before 
    verify(this.myView).displaySomething(); // Now I can do that. 
} 

我在想,如果是使用doAnswer方法,或者它是代碼味道,並且可以使用更好的設計嗎?

通常,我的演示者傾向於只使用其他對象(如一些調解器模式)並與視圖進行交互。我有幾百(〜400)行代碼的主持人。

同樣,它是不良設計的證明,還是主持人是冗長的(因爲它使用其他對象)是正常的?

有沒有人聽說過一些使用GWTP並乾淨地測試其演示者的項目?

我希望我全面解釋。

預先感謝您。

PS:我是Stack Overflow的新手,加上我的英語還是缺乏,如果我的問題需要改進,請告訴我。

回答

1

您可以使用ArgumentCaptor
查看此blog post詳細信息。

+0

這是完美的! +1 – EMM

0

如果我理解正確,您是在問關於設計/架構。

這不應該算作答案,這只是我的想法。

如果我跟隨代碼:

public void loadEmoticonPacks() { 
    executor.execute(new Runnable() { 
     public void run() { 
      pack = loadFromServer(); 
      savePackForUsageAfter(); 
     } 
    }); 
} 

我平時不指望執行人,只是檢查方法,通過加載和保存做具體的工作。所以這裏的執行程序只是防止UI線程中的長操作的工具。

如果我有這樣的:

accountManager.setListener(this); 
.... 
public void onAccountEvent(AccountEvent event) { 
.... 
} 

我將首先我們訂閱了事件的檢查(和退訂一些破壞),以及我會檢查onAccountEvent沒有預期的情況。

UPD1。可能在示例1中,更好的方法是提取方法loadFromServerAndSave並檢查它是否未在UI線程上執行,並檢查它是否按預期執行了所有操作。

UPD2。最好使用像Guava Bus這樣的框架來處理事件。

0

我們在我們的演示者測試中也使用這種doAnswer模式,通常它工作得很好。但有一點需要注意:如果你這樣測試,你可以有效地消除這個調用的異步特性,也就是說,在服務器調用啓動後立即執行回調。

這可能導致未被發現的競爭條件。要檢查這些問題,可以分兩步進行:在調用服務器時,答案方法只保存回調。然後,當你的測試合適的時候,你可以在你的答案中調用sometinh,如flush()或onSuccess()(我會建議爲此創建一個實用類,以便在其他情況下可以重用),以便可以控制何時回調結果真的叫。