web-dev-qa-db-ja.com

@Mockと@InjectMocksの違い

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

348
user2249972

@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...

}
424
Tom Verelst

これは@Mock@InjectMocksがどのように機能するかについてのサンプルコードです。

GamePlayerクラスがあるとしましょう。

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;
    }
}

ご覧のとおり、GameクラスはPlayerを実行するためにattackを必要とします。

@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クラスをモックするでしょう、そしてそれはwhenthenReturnメソッドを使った振る舞いです。最後に、@InjectMocksを使うことで、そのPlayerGameに入れます。

new Gameオブジェクトを作成する必要さえないことに注意してください。 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<String> 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<String> opponents;

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

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

  // ...

これは、MockitoがGameクラスのType Signature、つまりPlayerList<String>をチェックするためです。

118
aldok

あなたのテストクラスでは、テストされたクラスは@InjectMocksでアノテーションを付けられるべきです。これはMockitoにモックを注入するクラスを指示します。

@InjectMocks
private SomeManager someManager;

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

@Mock
private SomeDependency someDependency;

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

68
user2989087

@Mockアノテーションは、関係するオブジェクトを偽造します。

@InjectMocksアノテーションは、@Mockによって作成された異なる(そして関連する)モックを基礎となるオブジェクトに注入することを可能にします。

両方とも補完的です。

48
Mik378
  • @Mock あなたが必要とするクラスのためのモック実装を作成します。
  • @InjectMock はクラスのインスタンスを作成し、アノテーション @Mock でマークされているモックをそれに挿入します。

例えば

@Mock
StudentDao studentDao;

@InjectMocks
StudentService service;

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

ここではサービスクラス用のDAOクラスが必要です。そこで、それをモックしてサービスクラスインスタンスに注入します。同様に、Springフレームワークでは、すべての @Autowired BeanをjUnitsの @Mock でモックし、@InjectMocksを介してBeanにインジェクトすることができます。

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

このリンクはMockitoフレームワークの良いチュートリアルです

17
Sana Jahan

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

MockitoはMITライセンスの下でリリースされたJava用のオープンソーステストフレームワークです。それはあなたがきれいで単純なAPIで美しいテストを書くことを可能にする「モッキングフレームワーク」です。 Java空間にはさまざまなモックフレームワークがありますが、モックオブジェクトフレームワークには基本的に2つのタイプがあります。1つはプロキシ経由で実装され、もう1つはクラス再マッピング経由で実装されます。

Springのような依存性注入フレームワークでは、コードを変更することなくプロキシオブジェクトを注入することができます。モックオブジェクトは特定のメソッドが呼び出されることを期待しており、期待される結果を返します。

@InjectMocksアノテーションはテストオブジェクトのインスタンスをインスタンス化しようとし、テストオブジェクトのプライベートフィールドに@Mockまたは@Spyでアノテーションが付けられたフィールドを挿入します。

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

12
serup

@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...

}

それが良いやり方であるかどうかはあなたのアプリケーション設計に依存します。

8
tintin

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

例でさらに読むための参照: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/ /

3
avp

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

例えば:

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(){

   }

}
1
dev_2014

@InjectMocksは、 廃止予定 になります。

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

そして@avp 回答とリンク をフォローすることができます。

自動配線フィールドにInjectMocksアノテーションを使用してはいけない理由

1
user7294900

@InjectMocksアノテーションを使用すると、モックフィールドをテストオブジェクトに自動的に挿入できます。

以下の例では、@ InjectMocksがモックのdataMapをdataLibraryに挿入するために使用されています。

@Mock
Map<String, String> dataMap ;

@InjectMocks
DataLibrary dataLibrary = new DataLibrary();


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

        assertEquals("aMeaning", dataLibrary .getMeaning("aData"));
    }
1