2016-05-02 12 views
3

デバッグ中に私はMockito 1.10を使って何か信じられないほど奇妙なものを見つけました。私は誰かがここで知覚される動作を説明することを望んでいました:なぜMockitoはInputStreamで奇妙な動作をしていますか?

私が次を実行すると、スレッドがハングアップし、テストが返されません。作成されたJavaプロセスのCPUも天文学になります!

@Test(expected = IOException.class) 
public void mockitoWeirdness() throws IOException { 
    final InputStream mis = mock(InputStream.class); 
    doThrow(IOException.class).when(mis).read(); 
    ByteStreams.copy(mis, new ByteArrayOutputStream()); 
} 

次のように私は手動でこのメソッドをスタブすると、期待にIOExceptionがスローされます。

@Test(expected = IOException.class) 
public void nonMockitoExpected() throws IOException { 
    final InputStream mis = new InputStream() { 

     @Override 
     public int read() throws IOException { 
      throw new IOException(); 
     } 
    }; 
    ByteStreams.copy(mis, new ByteArrayOutputStream()); 
} 

どのように、なぜこの方法が失敗しているmockitoは素晴らしいだろう理解するすべてのヘルプ。

+0

私は 'ByteStreams.copy'の実装を知りませんが、1バイトを読み込む代わりに' read(byte []) 'を呼び出す' read() 'を呼び出さないかもしれません。 –

+0

' ByteStreams.copy read()の前にInputStreamの何かを呼び出します。私たちがこのクラスのコードを持っていれば、さらに調査するのに非常に役立つでしょう。 – Ray

+0

ByteStreamsは、このためのGoogleGuavaライブラリです。私はあなたがここで正しいと思います。私がクラスをスパイすると、その動作は成功します。これがどのような方法であるかについてもう少し調査します。 –

答えて

2

ByteStreamsの実装を見ると、のread(buf)メソッドが使用されていることがわかります。 ヌルが返されます。モックの定義がないため、コピーメソッドで無限ループが発生します。

default mock behaviourを変更するか、またはのread(buff)メソッドの定義を手動で追加することができます。

1

あなたは

final InputStream mis = Mockito.mock(InputStream.class, Mockito.CALLS_REAL_METHODS); 

javadoc状態

はそれらをスタブしていないときは、作業しているとき、この実装は参考にすることができInputStreamの本当のメソッドを呼び出すためにあなたのモックを設定することをお勧めしますレガシーコードで この実装が使用される場合、未確定メソッドは 実際の実装に委譲します。これはデフォルトで実際のメソッドを呼び出す部分モックオブジェクト を作成する方法です。

Mockitoは、デフォルトではすべてを模倣します。最初に使用したByteStreams#copyメソッドはInputStream#read(byte[])を呼び出します。 mockitoはそれを嘲笑しているので、ByteStreams#copyは "このストリームから読むことがもっとあります"と解釈して読み取りを続けます(無限ループ)0を返します。

Mockito.CALLS_REAL_METHODSを使用すると、Mockitoに実際の実装をInputStreamに呼び出すと、read()に委任されます。これは、例外をスローするようにスタブしています。