2012-01-20 16 views
3

私はその問題が一例で最もよく説明されていると思います。"tell、do not ask"フォロワークラスの単体テスト方法は?

public class MyService { 
    private OtherService theOther; 
    public void setTheOther(OtherService srv) { theOther = srv; } 

    public void myBusinessStuffFor(int id) { 
     theOther.applyToAllWith(id, new OtherService.Action() { 
      public void apply(Object whatever) { 
       doTheHardBusinessStuffWith(whatever); 
      } 
     } 
    } 

    private void doTheHardBusinessStuffWith(Object whatever) { 
     // here the business stuff provided by MyService 
    } 
} 

public interface OtherService { 
    void applyToAllWith(int id, Action action); 

    public interface Action { 
     void applyOn(Object whatever); 
    } 
} 

私はこのパターンが好きです。非常に結束しているからです。アクションインタフェースは、サービスとペアになっています。ビジネスロジックは多くのクラスで混乱することはありません。サブクラスはアクションにデータを提供するだけであり、ビジー状態である必要はありません。私はここからそれを採用した(http://jamesladdcode.com/?p=12)。問題は、 "doTheHardBusinessStuffWith(Object whatever)"メソッドの動作をテストするための良いソリューションが見つからないということです。モックではビジネスメソッドがどのように呼び出されるか気にする必要があります。しかし、どうすればいいのですか?私はmockitoを使って既にArgumentCaptureで試してみました。しかし、それはArgumentCaptureを悪用したために正しく感じられません。

クラスMyService.myBusinessStuffFor(int id)で使用されているパターンが名前を持っているかどうかを知りたいです(戦略パターンですか)? しかし私の主な質問は、このコードをOtherServiceのモックでテスト可能にする方法です。

答えて

-1

OtherServiceを嘲笑することについてお話します。私はあなたが使用しているモックフレームワークを知っていません。 applyToAllWithメソッドに渡されたActionのapplyOnメソッドを呼び出し、mockオブジェクトを引数として渡すモックを作成できるはずです。例えば、mockitoでは、これはこのようなものになるでしょう。

doAnswer(new Answer<Object>(){ 
    public Object answer(InvocationOnMock invocation){ 
     ((Action) invocation.getArguments()[ 1 ]).applyOn(mockObject); 
     return null; 
}}).when(mockOtherService).applyToAllWith(anyInt(), any(Action.class)); 
mockOtherServiceあなたは OtherServiceインターフェイス用に作成したモックで

、そしてmockObjectはあなたがdoTheBusinessHardStuffWithに渡すモック方です。

+0

これは私が探していたものです。誰かだけがこのパターンの名前を教えてくれたら、私は完全に満足するでしょう。 –

+0

申し訳ありませんが、私はものの名前を知っているとあまりよくありません。あなたのコードをテストする常識的な方法であるように思えます。私はこの特定のパターンの名前を知らない。 –

+0

コマンドパターン:http://en.wikipedia.org/wiki/Command_pattern –

1

この場合、他のサービスは実際にはビジネスサービスではありません。その唯一の責任は、指定されたIDからオブジェクトを見つけて、これらのオブジェクトに与えられたアクションを適用することです。機能上、これは次のコードに相当します。

Set<Object> objects = otherService.getObjectsWithId(id); 
for (Object o : objects) { 
    doTheHardBusinessStuffWith(o); 
} 

doTheHardBusinessStuffWithを保護します。このメソッドの単体テストを作成します。これは、ビジネスロジックをテストする最も重要な単体テストです。

あなたが本当にユニットテストをしたいのであれば、モックOtherServiceを作成することです(ここではこのモックをあなた自身で実装することを意味します)。これはオブジェクトのセットから構築され、セット内のすべてのオブジェクト。 doTheHardBusinessStuffWithメソッドが嘲笑され、あなたが偽装したOtherServiceとともに注入されているMyServiceの部分モックを作成します。部分模擬でmyBusinessStuffForを呼び出し、doTheHardBusinessStuffWithがオブジェクトセットのすべてのオブジェクトで呼び出されていることを確認します。

+0

doTheHardBusinessStuffWith protectedをこれまでの選択肢にすることはできません。それは私的な行動であり、私的であるべきです。 myBusinessStuffForはこのクラスのエントリポイントなので、ユニットテストを行う必要があります。オブジェクトを収集する動作は、私が隠したいものとまったく同じです。生のオブジェクトを収集してビジネスロジックを適用するには、常にループを2回実行する必要があります。そして、それは複数のオブジェクトを扱うことができるだけOtherServiceによって知られています。また、OtherServiceをアダプターとして実装してアクションを呼び出すと、他の用途では難しくなる可能性があります。 –

+0

そして、それを 'myBusinessStuffFor'のテストの一部としてテストします。しかし、あなたはあなたの人生を困難にしています。 –

関連する問題