1. ホーム
  2. java

[解決済み] モックオブジェクトの初期化 - MockIto

2022-03-03 14:03:35

質問

MockItoを使用してモックオブジェクトを初期化する方法はたくさんあります。 その中で一番良い方法は何ですか?

1.

 public class SampleBaseTestCase {

   @Before public void initMocks() {
       MockitoAnnotations.initMocks(this);
   }

@RunWith(MockitoJUnitRunner.class)

mock(XXX.class);

他に良い方法があれば教えてください。

解決方法は?

モックの初期化について を使用すると、ランナーまたは MockitoAnnotations.initMocks は厳密には同等の解決策です。のjavadocから。 MockitoJUnitRunner(モッキートジュニットランナー :

JUnit 4.5のランナーはMockでアノテーションされたモックを初期化するので、MockitoAnnotations.initMocks(Object)を明示的に使用する必要はないです。モックは各テスト・メソッドの前に初期化されます。


最初の解決策( MockitoAnnotations.initMocks ) は、すでに特定のランナーを設定している場合に使用できます ( SpringJUnit4ClassRunner など) をテストケース上で実行します。

2つ目の解決策は、( MockitoJUnitRunner は、より古典的で私のお気に入りです。コードがよりシンプルになります。ランナーを使うことで フレームワークの使用に関する自動検証 (によって記述される デービッド・ウォレス この回答 ).

どちらのソリューションも、テストメソッド間でモック(とスパイ)を共有することができます。と組み合わせることで @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アノテーションによるものです。このアノテーションを使うと "あなたはコードの痛みを失う"。 (の素晴らしいコメント参照)。 ブライス )


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がどのように動作するかを明確に示している(私の ArticleManager がインスタンス化される)。定型的なコードがない。

短所:テストが自己完結していないため、コードの苦痛が少ない。