Mockitoフレームワークにおける@Mock
と@InjectMocks
の違いは何ですか?
@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...
}
これは、「@ 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を使用すると、その Player
が 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がゲームクラスの「タイプシグネチャ」(「プレイヤー」と「リスト<文字列>」)をチェックするためです。
テストクラスでは、テストしたクラスに「@InjectMocks」と注釈を付ける必要があります。 これは、モックを注入するクラスをモッキトに指示します。
@InjectMocks
private SomeManager someManager;
それ以降、クラス内の特定のメソッドまたはオブジェクト(この場合は SomeManager
)をモックで置き換えることを指定できます。
@Mock
private SomeDependency someDependency;
この例では、「SomeManager」クラス内の「SomeDependency」がモックされます。
- @ 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がベースとしているモッキングフレームワークは、モックオブジェクトを作成する機能を提供するフレームワークです(古い言葉で言うと、これらのオブジェクトは依存する機能のシャントとして機能するため、シャントと呼ばれます)。 つまり、モックオブジェクトは、あなたのコードが依存している実際のオブジェクトを模倣するために使用され、あなたはモッキングフレームワークでプロキシオブジェクトを作成します。 モックオブジェクトをテストに使うことで、通常のユニットテストから統合テストに移行することになります。
MockitoはMITライセンスで公開されているオープンソースのJava用テストフレームワークで、クリーンでシンプルなAPIで美しいテストを書くことができるquot;mocking framework"です。Javaには様々なモッキングフレームワークがありますが、基本的にモックオブジェクトのフレームワークにはプロキシで実装されたものとクラスリマッピングで実装されたものの2種類があります。
Springのような依存性注入フレームワークでは、コードを修正することなくプロキシオブジェクトを注入することができます。モックオブジェクトは、あるメソッドが呼ばれることを期待し、期待した結果を返すことになります。
InjectMocksアノテーションは、テストオブジェクトのインスタンスを作成し、
@Mockまたは
@Spy`でアノテーションされたフィールドをテストオブジェクトのプライベートフィールドにインジェクトしようとします。
MockitoAnnotations.initMocks(this)
を呼び出すと、テストオブジェクトをリセットしてモックを再初期化するので、 @Before
/ @BeforeMethod
アノテーションでこれを持つことを忘れないようにしてください。
@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...
}
それが良い習慣かどうかは、アプリケーションの設計に依存します。
多くの人々がここで「@Mock」対「@InjectMocks」について素晴らしい説明をしました。 私はそれが好きですが、私たちのテストとアプリケーションは、「@ InjectMocks」を使用する必要がないように書かれるべきだと思います。
例をさらに読むためのリファレンス:https://tedvinke.wordpress.com/2014/02/13/mockito-why-why-you-should-not-injectmocks-annotation-to-autowire-fields/。
@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(){
}
}
@InjectMocks注釈を使用して、模 ⁇ フィールドをテストオブジェクトに自動的に注入できます。
以下の例では、@ InjectMocksを使用して、モックデータマップを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"));
}