2012-02-02 5 views
18

orginalメソッドを呼び出します。Mockito - 実際のオブジェクトをスパイすると、次のコードを想像してみて

List list = ..... 
List spy = spy(list); 
doThrow(new NullpointerException()).when(spy).get(0); 

doThrow(....)list.get(0)を実行 - これは全く意味がありません。ここでメソッドを呼び出さないように模擬動作を定義したいと思っています。

EDIT: リストはCGLIBで装飾されています。 CGLIBプロキシを削除すると、Mockitoは期待どおりに動作します。任意のアイデアどのようにCGLIBのプロキシを使用してそのような問題を解決するには?

おかげで、 マチェイ

+0

これは実際にはビルダーパターンを使用するmockitoの構文です。 (そう多くの他の模造フレームワークのように) –

+0

私がMockitoを知る限り、あなたのコードは正しいです。ドキュメンテーションでは、 'doThrow'はvoidメソッドのためのものだと言います。これが問題かどうかを確認するには 'clear()'を使います。しかし、なぜdoThrowが 'doReturn'のような非voidメソッドでも動作してはならないのは本当に想像できません。 – flyx

+0

あなたがここで何を求めているか分かりません。はい、doThrow()をvoid以外のメソッドでも使用できます。ドキュメントがvoidメソッドを記述する理由は、スタブスローの2番目の構文があり、voidメソッドでは機能せず、ドキュメント内でdoThrowする前に提示されるためです。あなたの例のget(0)は、実際のリストではなく、スパイでのみ呼び出されます。スパイは、それがdoThrowのコンテキスト内にあることを知っているので、REAL get(0)を呼び出す代わりに、代わりにそれをスタブします。それはあなたが求めていることですか?もしそうなら、私はこのコメントを答えに変えるでしょう。 –

答えて

6
import static org.mockito.Mockito.doThrow; 
import static org.mockito.Mockito.spy; 

import java.lang.reflect.Method; 

import org.junit.Test; 

import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 

public class MockitoSpyTest { 

    @Test 
    public void execTest() { 

     System.out.println("*** TEST 1 ***"); 
     System.out.println("Test on unmodified object"); 
     MySet ms = new MySetImpl(); 
     ms.set("test value"); 
     System.out.println("Set contains: " + ms.get()); 

     // decorate ms1 with easymock 
     System.out.println("\n*** TEST 2 ***"); 
     MySet spyMs = spy(ms); 
     doThrow(new NullPointerException("my test nullpointer")).when(spyMs).get(); 
     System.out.println("Test decorated object with SPY"); 
     spyMs.set("test value"); 
     try { 
      System.out.println("Set contains: " + spyMs.get()); 
     } catch (NullPointerException e) { 
      System.out.println("NullPointerException - as expected"); 
     } 

     // Enhance call with CGLIB 
     System.out.println("\n*** TEST 3 ***"); 
     System.out.println("Test on CGLIB decorated object"); 
     Enhancer enc = new Enhancer(); 
     enc.setSuperclass(MySetImpl.class); 
     enc.setInterfaces(new Class[] { MySet.class }); 
     enc.setCallback(new MethodInterceptor() { 

      @Override 
      public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
       if ("get".equals(method.getName())) { 
        System.out.println("CGLIB decorated GET call"); 
       } 
       return proxy.invokeSuper(obj, args); 
      } 
     }); 
     MySet ms1 = (MySet) enc.create(); 
     ms1.set("test value"); 
     System.out.println("Set contains: " + ms1.get()); 

     // decorate ms1 with easymock 
     System.out.println("\n*** TEST 4 ***"); 
     System.out.println("Test on CGLIB decorated object with SPY"); 
     MySet spyMs1 = spy(ms1); 
     doThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get(); 
     spyMs1.set("test value"); 
     System.out.println("Set contains: " + spyMs1.get()); 
    } 

    public interface MySet { 
     void set(String val); 

     String get(); 
    } 

    public static class MySetImpl implements MySet { 
     String val; 

     public void set(String val) { 
      this.val = val; 
      System.out.println("Original SET call:" + val); 
     } 

     public String get() { 

      System.out.println("Original GET call:" + val); 
      return val; 
     } 

    } 
} 

例の出力を生成します。

*** TEST 1 *** 
Test on unmodified object 
Original SET call:test value 
Original GET call:test value 
Set contains: test value 

*** TEST 2 *** 
Test decorated object with SPY 
Original SET call:test value 
NullPointerException - as expected 

*** TEST 3 *** 
Test on CGLIB decorated object 
Original SET call:test value 
CGLIB decorated GET call 
Original GET call:test value 
Set contains: test value 

*** TEST 4 *** 
Test on CGLIB decorated object with SPY 
CGLIB decorated GET call 
Original GET call:test value 
Original SET call:test value 
CGLIB decorated GET call 
Original GET call:test value 
Set contains: test value 

TEST 2TEST 4NullPointerExceptionget上のコールスローする必要があります - mockitoスパイに基づく: "TEST 4が" スロー期待しないdoThrow(new NullPointerException("my test nullpointer")).when(spyMs1).get();

を既にCGLIBで装飾されているため例外です - CGLIb呼び出しが実行されていることをコンソールで確認することもできます:GLIB decorated GET callとspyオブジェクトを呼び出さないでください。 CGLIBプロキシでSpring AOPを使用する場合、同じ効果が得られます。

+0

優秀な例。しかし、私はこれがどのように答えになったのか分かりませんでした。私はMockitoでSpring AOPを使用しているときに同じ問題を抱えています。私がスパイしている方法についてはスパイできなかった。 – supertonsky

+0

supertonsky、答えは、一言で言えば、CgLibで強化されたオブジェクトにMockitoのスパイを作成できないということです。 :( – bcody

0
Mockito.doThrow(new NullpointerException()).when(spy).get(0); 

私はここでの問題は、あなたが部分的モックをやろうとしているので、あなたのテストクラスに注釈を持たなければならないということだと思う:

@PrepareForTest(List.class) 

これは動作しても動作しなくてもよい。例外処理をテストする私のコードを見ると、私はいつも完全にモックされたオブジェクトで行いました。部分的に嘲笑されたオブジェクトではありませんでした。また、私はPowerMockitoを広範に利用して部分的な嘲笑をしているので、必要なことをライブラリが行うことが可能です。上記

+0

あなたは混乱しています。 ** A。** Mockitoは、[Mockito#spy()](http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#spy(T))を使用して、しばらくの間部分的なモックを行うことができます。しかし、Mockitoは最終的なクラスや最終的なメソッドをモックしません。それがPowerMockが役立つかもしれません。 ** B。**あなたは '@PrepareForTest(List.class)'を言及しています。これは、2つの理由から無関係で間違っています:1.リストはインターフェイスなので、モックに問題はありません。システムクラスのために働く(エージェントを追加することなく)。 – Brice

+0

これは、パワーモックが別のプロキシを生成するため動作します。私はそれを試して、私はjavassisの例外を取得しています - この場合、私たちはcglibとjavassisの間に競合があります –

+4

あなたはうまくないですか?人々を数か月後に下降させる。 APIが1年後に変更されたら、どうしてそれを罰するのですか? –

関連する問題