@Mockと@InjectMocksの違い


回答:


542

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

}

2
短く簡潔な答え。参考になった;)
Chaklader Asfak Arefe

これは推移的な依存関係で機能しますか、それとも直接メンバーのみで機能しますか?
Pierre Thibault

@PierreThibault注入モックは直接のメンバーのみのために動作しますが、あなたは深いスタブ許可するようにモックを設定することができますstatic.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/...
トムVerelst

1
私は...ちょっとコメントが私のお尻を保存することを....これはオンライン記事のほとんどよりもはるかに明確であると感じ
IHC_Applroid

コンテキストのような@Mockアノテーションでは提供できないアイテムがあります。メインクラスにそれをどのように提供できますか?
Mahdi

220

これは、方法@Mock@InjectMocks動作に関するサンプルコードです。

クラスがあるGameとしPlayerます。

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メソッドを使用します。最後に、@InjectMocksMockitoを使用すると、それがに入れPlayerられGameます。

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がチェックするためだType Signatureあるゲームのクラス、のPlayerList<String>


16
この例では、それは受け入れられた答えになるはずです。
AnnaKlein

4
私もこれが最高の方法だと思います
Evgeniy Dorofeev

4
これがベストアンサートリプルだと思います。
Harvey Dent

1
私は時々、モックを使ったテストを理解し、クラスのために設計するのが難しいことに気づきます。ただし、この例は概要を説明するのに役立ちます。
Chaklader Asfak Arefe

1
多くのおかげで:)より良い説明で要点に。
Rishi

80

テストクラスでは、テストするクラスにで注釈を付ける必要があり@InjectMocksます。これは、モックをどのクラスに注入するかをMockitoに指示します。

@InjectMocks
private SomeManager someManager;

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

@Mock
private SomeDependency someDependency;

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


6
someManagerに複数のコンストラクタがある場合、これは機能しますか?someManagerに5つのコンストラクターがある場合、どのコンストラクターを使用するかをどのようにして知ることができますか?
j2emanue 2017

51

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

@InjectMocksアノテーションを使用すると、によって作成されたさまざまな(および関連する)モックを基礎となるオブジェクトに注入でき@Mockます

どちらも補完的です。


1
同じオブジェクトで一緒に使用できますか?
IgorGanapolsky 2017

1
あなたの要件の小さな例はありますか?
Mik378

(Mockito Spyを介して)スパイする必要のあるクラスがあり、このクラスにはコンストラクターがあります。だから私は@InjectMocksこのクラスを構築してそれをスパイするのにも使用することを考えていました
IgorGanapolsky 2017

1
それはあなたが探しているものですか?stackoverflow.com/a/35969166/985949
Mik378

23
  • @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フレームワークの優れたチュートリアルがあります


13

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

MockitoはMITライセンスの下でリリースされたJava用のオープンソースのテストフレームワークで、「モックフレームワーク」であり、クリーンでシンプルなAPIを使用して美しいテストを記述できます。Java空間にはさまざまなモックフレームワークがありますが、モックオブジェクトフレームワークには、主に2つのタイプがあります。1つはプロキシを介して実装され、もう1つはクラスの再マッピングを介して実装されます。

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

@InjectMocks注釈は、注釈付きでテストオブジェクトのインスタンスと注入フィールドインスタンス化しようとし@Mockたり@Spy、テストオブジェクトのプライベートフィールドにします。

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


2
「テストでモックオブジェクトを使用することで、基本的に通常の単体テストから統合テストに移行する」とは言いません。私にとって、モックはユニットテストのためにテストされるフィクスチャを分離することです。統合テストでは、実際のモックされていない依存関係を使用します。
WesternGun 2018

10

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

}

これが良い習慣かどうかは、アプリケーションの設計によって異なります。


someManagerに3つの異なるコンストラクターがある場合、どのコンストラクターを使用するかをどのようにして知るのでしょうか?
j2emanue 2017

モックされていない場合、someManagerの内容をどのように確認しますか?
IgorGanapolsky 2017

5

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

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


1
これは長期的な解決策のようです。
Vinayak Dornala

4

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

   }

}

4

@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"));
    }

3

廃止予定@InjectMocksあることを確認します

@InjectMocksの廃止とMockito 3/4での削除のスケジュール

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

フィールドを自動配線するためにInjectMocksアノテーションを使用すべきでない理由


3

上記の回答はカバーしていますが、欠けていると思われる詳細な詳細を追加しようとしました。それらの背後にある理由(なぜ)。

ここに画像の説明を入力してください


図:

Sample.java
---------------
    public class Sample{
        DependencyOne dependencyOne;
        DependencyTwo dependencyTwo;


        public SampleResponse methodOfSample(){
            dependencyOne.methodOne();
            dependencyTwo.methodTwo();

            ...

            return sampleResponse;
        }
    }

SampleTest.java
-----------------------
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class})
public class SampleTest{

    @InjectMocks
    Sample sample;

    @Mock
    DependencyOne dependencyOne;

    @Mock
    DependencyTwo dependencyTwo;

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

    public void sampleMethod1_Test(){
        //Arrange the dependencies
        DependencyResponse dependencyOneResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyOne).methodOne();

        DependencyResponse dependencyTwoResponse = Mock(sampleResponse.class);
        Mockito.doReturn(dependencyOneResponse).when(dependencyTwo).methodTwo();

        //call the method to be tested
        SampleResponse sampleResponse = sample.methodOfSample() 

        //Assert
        <assert the SampleResponse here>
    }
}

参照

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.