7

私は GWTP を使用しており、コントラクト レイヤーを追加してプレゼンターとビューの間の知識を抽象化しています。GWTP の結果にはかなり満足しています。Mockito でプレゼンターをテストしています。

しかし、時が経つにつれて、テストできれいなプレゼンターを維持するのが難しいことに気付きました。それを改善するために私が行ったいくつかのリファクタリングがありますが、私はまだ満足していません.

以下が問題の核心であることがわかりました。私のプレゼンターは、多くの場合、非同期呼び出しを必要とするか、通常、プレゼンター フローを続行するためにコールバックを使用してオブジェクト メソッドを呼び出す必要があります (通常はネストされています)。

例えば ​​:

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

私のテストでは、モック化された PopulationManager オブジェクトのpopulation() 呼び出しを検証するために終了しました。次に、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));

私はそれがより冗長になるようにコードを因数分解しました(そして内部的に引数の位置にあまり依存しません):

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 にかなり慣れていません。また、英語がまだ不十分です。質問に改善が必要な場合は、教えてください。

4

3 に答える 3

1

使用できますArgumentCaptor:詳細については
、このブログ投稿を確認してください。

于 2012-12-07T09:42:25.040 に答える
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 のようなフレームワークを使用することをお勧めします。

于 2012-12-07T13:08:07.413 に答える
0

プレゼンター テストでもこの doAnswer パターンを使用していますが、通常は問題なく動作します。ただし、注意点が 1 つあります。このようにテストすると、呼び出しの非同期性が効果的に取り除かれます。つまり、サーバー呼び出しが開始された直後にコールバックが実行されます。

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

于 2013-04-21T06:00:42.503 に答える