モックの初期化では、ランナーまたはを使用することMockitoAnnotations.initMocks
は厳密に同等のソリューションです。MockitoJUnitRunnerのjavadocから:
JUnit 4.5ランナーは、Mockで注釈が付けられたモックを初期化するため、MockitoAnnotations.initMocks(Object)を明示的に使用する必要はありません。モックは、各テストメソッドの前に初期化されます。
最初のソリューション(を使用)は、テストケースで特定のランナー(たとえば)をMockitoAnnotations.initMocks
既に構成している場合に使用できます。SpringJUnit4ClassRunner
2番目の解決策(を使用MockitoJUnitRunner
)は、より古典的で私のお気に入りです。コードはもっと単純です。ランナーを使用すると、フレームワークの使用を自動検証できるという大きな利点があります(この回答では@David Wallaceが説明しています)。
どちらのソリューションでも、テストメソッド間でモック(およびスパイ)を共有できます。と組み合わせると、@InjectMocks
単体テストを非常に迅速に作成できます。ボイラープレートのモックコードが削減され、テストが読みやすくなります。例えば:
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock(name = "database") private ArticleDatabase dbMock;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks private ArticleManager manager;
@Test public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
manager.finishArticle();
verify(database).removeListener(any(ArticleListener.class));
}
}
長所:コードは最小限です
短所:黒魔術。IMOは、主に@InjectMocksアノテーションが原因です。このアノテーション を使用すると、「コードの苦痛を和らげることができます」 ( @Briceのすばらしいコメントを参照)
3番目の解決策は、各テストメソッドでモックを作成することです。@mlkの回答で説明されているように、「自己完結型テスト」を使用できます。
public class ArticleManagerTest {
@Test public void shouldDoSomething() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
長所:APIがどのように機能するかを明確に示しています(BDD ...)
短所:より多くの定型コードがあります。(モックの作成)
私の推薦は妥協です。@Mock
注釈を付けて使用しますが、 :@RunWith(MockitoJUnitRunner.class)
は使用しないでください。@InjectMocks
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@Test public void shouldDoSomething() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
長所:APIがどのように機能するか(myがどのようにArticleManager
インスタンス化されるか)を明確に示します。ボイラープレートコードはありません。
短所:テストは自己完結型ではなく、コードの苦痛が少ない