2012-12-06 9 views
8

私はGWTPを使用しており、PresenterとViewの間の知識を抽象化するためのコントラクトレイヤーを追加しています.GWTPの結果はかなり満足しています。 私はMockitoでプレゼンターをテストしています。非同期呼び出しによるGWTPプレゼンターのテスト

しかし、時間がたつにつれ、私はテストで清潔なプレゼンターを維持することが難しいことが分かった。 改善のために行ったリファクタリングのものがいくつかありますが、まだ満足していませんでした。 私の発表者は非同期呼び出しを頻繁に必要とするか、一般的にプレゼンターのフローを続けるためにコールバックを使用してオブジェクトメソッドを呼び出す必要があります(通常は入れ子になっています)。例えば

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

私のテストでは、私は嘲笑PopulationManagerオブジェクトの人口()の呼び出しを検証するために終わりました。次に、doSomeStufWithTheView()メソッドで別のテストを作成します。

しかし私は、それが悪い設計であることをかなり早く発見しました。プレゼンターの機能は変わっていませんが、変更やリファクタリングが多くのテストを中断し、他のユーザーから作成を余儀なくされました。 プラスコールバックが効果的に機能しているかどうかはテストしませんでした。

だから、私はプレゼンターのテストの流れを壊さないためにdoAnswer方法mockito使用しようとしました:

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)); 

それはそれほど冗長(および引数の位置に内部的にあまり依存)であるために、私はコードを織り込ん:

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:私の質問に何か改善が必要な場合は、私の英語はまだ足りないです。

答えて

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パターンはプレゼンターテストでも使用されていますが、通常は正常に動作します。 1つの注意点:このようにテストすると、呼び出しの非同期性が効果的に取り除かれます。つまり、コールバックはサーバー呼び出しが開始された直後に実行されます。

これは、未知の競合状態につながる可能性があります。これらを確認するには、これを2段階のプロセスにすることができます。サーバーを呼び出すとき、応答メソッドはコールバックのみを保存します。あなたのテストでそれが適切であれば、答えにflush()やonSuccess()などのsometinhを呼び出す(これは他の状況で再利用できるユーティリティクラスを作ることを提案する)ので、結果のコールバックが実際に呼び出されます。

関連する問題