Mockito~doReturn/whenとwhen/thenReturnの違い
mockitoについての全投稿は/tag/mockitoにあるので参照されたい
Mockitoのスタブ化には二通りの書き方がある。以下のようなものだ。
import org.junit.*;
import org.mockito.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class Sample {
@Mock Login login;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
// こちらか
doReturn(true).when(login).doit(anyString(), anyString());
// あるいはこちら
when(login.doit(anyString(), anyString())).thenReturn(true);
assertTrue(login.doit("a", "b"));
}
public interface Login {
public boolean doit(String name, String password);
}
}
この違いは何だろうか?
StackOverflowでの答え1
Mockito – difference between doReturn() and when()に解説してくれている人がいる。
二つの構文はおおよそ同じだ。しかし、doReturn/whenはいつでも使えるのに対し、when/thenReturnは使えないケースがある。voidメソッドをスタブ化するのがその一つだ。他の例としては、Mockitoのspyを使う場合や、一つのメソッドを複数回スタブ化する場合だ。
doReturn/whenには無い、when/thenReturnがもたらしてくれるものとしては、コンパイル時の返り値タイプチェックだ。しかし、これにはほぼ価値が無いと思う。もし型が間違っていれば、テストを走らせるやいなやわかることだからね。
強くおすすめするのは、doReturn/whenのみを使うことだ。片方でできるのに、二つの構文を学ぶ理由は無いよね。
僕の書いたForming Mockito “grammers”を読んでみて欲しい。今回の質問に非常に近い、詳細な答えを書いている。
StackOverflowでの答え2
上述のForming Mockito “grammers”における回答者の答え。
when/thenReturn、when/thenThrow、when/then構文には様々不利な点がある。例えば、
- when/thenReturnでは、返り値がワイルドカード付ジェネリックの場合で、同じ型を返したい場合には、コンパイラの警告が不可避だ。
- voidメソッドにはwhen/thenThrowが使用できない。
- Mockitoのspyにはこれらの構文は使用できない。
- モックオブジェクト、メソッド、引数のそれぞれの組み合わせに対して一度しかwhenを呼び出せない。モックに対してreset()を行わない限りは。
- 引数マッチャーを使用中に、一つのモックオブジェクト、メソッド、引数の組み合わせに対して、複数回whenを呼び出すと、問題を起こしかねない。
これらのケースを覚えておくのは難しいと感じた。だから、when/thenReturn, when/thenThrow, when/thenがいかなる場合に機能して機能しないかを追うよりも、おすすめは、これらは完全に排除することだ。代替の doReturn/when, doThrow/when, doAnswer/whenを使うってこと。
つまり、doReturn/when, doThrow/when,doAnswer/whenを使う場合もあるということではなく、いつもこれらのメソッドを使うということだ。when/thenReturn, when/thenThrow, when/thenを学習する必要は無い。
注意して欲しいのは、doReturn, doThrow, doAnswerが、 thenReturn, thenThrow, thenと同じく互いにチェイン可能だということ、これらに存在しないのは、一度のdoReturn, doThrow, doAnswerの呼び出しで複数の値を返すことだ(あるいは、複数の例外を返したり、複数のAnswerを行うこと)。でも、これが必要なのは稀だと思うから、重大なことではない。
※訳注:2.1.0から、doReturn,doThrowは複数の値を返せるようになっている。
もう一つ、doReturnの取るに足らない弱点がある。コンパイル時の引数タイプチェックができないことだ、when/thenReturnのようには。だから、引数タイプが間違っている場合は、テストの実行まではわからない。率直に言って、僕は気にしないね。
要約すれば、僕は二年以上Mockitoを使ってきており、常に doReturn, doThrow, doAnswer を使うのがMockitoのベスト・プラクティスだと思ってる。他のユーザは不賛成だけどね。
ディスカッション
コメント一覧
まだ、コメントがありません