Mockと@InjectMocksの違い

Mockitoフレームワークにおける@Mock@InjectMocksの違いは何ですか?

質問へのコメント (1)

@Mock はモックを作成する。@InjectMocks はクラスのインスタンスを作成し、@Mock (または @Spy) アノテーションで作成されたモックをこのインスタンスにインジェクトする。

これらのモックを初期化してインジェクトするには、@RunWith(MockitoJUnitRunner.class)または Mockito.initMocks(this) を使用する必要があることに注意してください。

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

     //tests...

}
解説 (5)

これは、「@ Mock」と「@ InjectMocks」のしくみのサンプルコードです。

「ゲーム」と「プレイヤー」のクラスがあるとします。

class Game {

    private Player player;

    public Game(Player player) {
        this.player = player;
    }

    public String attack() {
        return "Player attack with: " + player.getWeapon();
    }

}

class Player {

    private String weapon;

    public Player(String weapon) {
        this.weapon = weapon;
    }

    String getWeapon() {
        return weapon;
    }
}

ご覧のとおり、「ゲーム」クラスでは「攻撃」を実行するには「プレイヤー」が必要です。

@RunWith(MockitoJUnitRunner.class)
class GameTest {

    @Mock
    Player player;

    @InjectMocks
    Game game;

    @Test
    public void attackWithSwordTest() throws Exception {
        Mockito.when(player.getWeapon()).thenReturn("Sword");

        assertEquals("Player attack with: Sword", game.attack());
    }

}

MockitoはPlayerクラスをモックし、「when」および「thenReturn」メソッドを使用した動作です。 最後に、 @ InjectMocks Mockitoを使用すると、その PlayerGameになります。

「新しいゲーム」オブジェクトを作成する必要さえないことに注意してください。 Mockitoが注入します。

// you don't have to do this
Game game = new Game(player);

@Spy注釈を使用して同じ動作を取得します。 属性名が異なっていても。

@RunWith(MockitoJUnitRunner.class)
public class GameTest {

  @Mock Player player;

  @Spy List enemies = new ArrayList();

  @InjectMocks Game game;

  @Test public void attackWithSwordTest() throws Exception {
    Mockito.when(player.getWeapon()).thenReturn("Sword");

    enemies.add("Dragon");
    enemies.add("Orc");

    assertEquals(2, game.numberOfEnemies());

    assertEquals("Player attack with: Sword", game.attack());
  }
}

class Game {

  private Player player;

  private List opponents;

  public Game(Player player, List opponents) {
    this.player = player;
    this.opponents = opponents;
  }

  public int numberOfEnemies() {
    return opponents.size();
  }

  // ...

これは、Mockitoがゲームクラスの「タイプシグネチャ」(「プレイヤー」と「リスト」)をチェックするためです。

解説 (5)

テストクラスでは、テストしたクラスに「@InjectMocks」と注釈を付ける必要があります。 これは、モックを注入するクラスをモッキトに指示します。

@InjectMocks
private SomeManager someManager;

それ以降、クラス内の特定のメソッドまたはオブジェクト(この場合は SomeManager)をモックで置き換えることを指定できます。

@Mock
private SomeDependency someDependency;

この例では、「SomeManager」クラス内の「SomeDependency」がモックされます。

解説 (1)

アノテーション @Mock は、当該オブジェクトをモックします。

InjectMocksアノテーションは、@Mock`で作成された様々な(関連する)モックを基本オブジェクトにインジェクトすることができます。

両者は補完関係にある

解説 (4)

- @ Mock は、必要なクラスのモック実装を作成します。 -@InjectMock はクラスのインスタンスを作成し、注釈@Mock でマークされたモックをそれに注入します。

例えば。

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

ここでは、サービスクラスのDAOクラスが必要です。 したがって、モックしてサービスクラスのインスタンスに注入します。 同様に、春のフレームワークでは、すべての@ Autowired 豆をjUnitsの @ Mock でモックし、@ InjectMocksを介して豆に注入できます。

MockitoAnnotations.initMocks(this)メソッドは、これらのモックを初期化し、すべてのテストメソッドに注入するため、 setUp()メソッドで呼び出す必要があります。

このリンクには、Mockitoフレームワークに適したチュートリアルがあります

解説 (0)

Mockitoがベースとしているモッキングフレームワークは、モックオブジェクトを作成する機能を提供するフレームワークです(古い言葉で言うと、これらのオブジェクトは依存する機能のシャントとして機能するため、シャントと呼ばれます)。 つまり、モックオブジェクトは、あなたのコードが依存している実際のオブジェクトを模倣するために使用され、あなたはモッキングフレームワークでプロキシオブジェクトを作成します。 モックオブジェクトをテストに使うことで、通常のユニットテストから統合テストに移行することになります。

MockitoはMITライセンスで公開されているオープンソースのJava用テストフレームワークで、クリーンでシンプルなAPIで美しいテストを書くことができるquot;mocking framework"です。Javaには様々なモッキングフレームワークがありますが、基本的にモックオブジェクトのフレームワークにはプロキシで実装されたものとクラスリマッピングで実装されたものの2種類があります。

Springのような依存性注入フレームワークでは、コードを修正することなくプロキシオブジェクトを注入することができます。モックオブジェクトは、あるメソッドが呼ばれることを期待し、期待した結果を返すことになります。

InjectMocksアノテーションは、テストオブジェクトのインスタンスを作成し、@Mockまたは@Spy`でアノテーションされたフィールドをテストオブジェクトのプライベートフィールドにインジェクトしようとします。

MockitoAnnotations.initMocks(this) を呼び出すと、テストオブジェクトをリセットしてモックを再初期化するので、 @Before / @BeforeMethod アノテーションでこれを持つことを忘れないようにしてください。

解説 (1)

@Tomで言及されているアプローチで得られる利点の1つは、SomeManagerにコンストラクターを作成する必要がないことです。そのため、クライアントをインスタンス化するように制限します。

@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {

    @InjectMocks
    private SomeManager someManager;

    @Mock
    private SomeDependency someDependency; // this will be injected into someManager

    //You don't need to instantiate the SomeManager with default contructor at all
   //SomeManager someManager = new SomeManager();    
   //Or SomeManager someManager = new SomeManager(someDependency);

     //tests...

}

それが良い習慣かどうかは、アプリケーションの設計に依存します。

解説 (2)

多くの人々がここで「@Mock」対「@InjectMocks」について素晴らしい説明をしました。 私はそれが好きですが、私たちのテストとアプリケーションは、「@ InjectMocks」を使用する必要がないように書かれるべきだと思います。

例をさらに読むためのリファレンス:https://tedvinke.wordpress.com/2014/02/13/mockito-why-why-you-should-not-injectmocks-annotation-to-autowire-fields/

解説 (1)

@Mockは従属豆の参照を宣言/モックするために使用され、 @InjectMocksはテストが作成されている豆をモックするために使用されます。

例:

public class A{

   public class B b;

   public void doSomething(){

   }

}

クラス Aのテスト:

public class TestClassA{

   @Mocks
   public class B b;

   @InjectMocks
   public class A a;

   @Test
   public testDoSomething(){

   }

}
解説 (0)

@InjectMocks注釈を使用して、模 ⁇ フィールドをテストオブジェクトに自動的に注入できます。

以下の例では、@ InjectMocksを使用して、モックデータマップをdataLibraryに注入しています。 .

@Mock
Map dataMap ;

@InjectMocks
DataLibrary dataLibrary = new DataLibrary();

    @Test
    public void whenUseInjectMocksAnnotation_() {
        Mockito.when(dataMap .get("aData")).thenReturn("aMeaning");

        assertEquals("aMeaning", dataLibrary .getMeaning("aData"));
    }
解説 (0)

@InjectMocks非推奨になることに注意してください。

@InjectMocksを非推奨にし、Mockito 3/4での削除のスケジュール。

@avp 回答とリンクを次のようにフォローできます。

InjectMocks注釈をAutowireフィールドに使用しない理由。

解説 (0)