Difference between @Mock and @InjectMocks
@Mock
creates a mock. @InjectMocks
creates an instance of the class and injects the mocks that are created with the @Mock
(or @Spy
) annotations into this instance.
Note you must use @RunWith(MockitoJUnitRunner.class)
or Mockito.initMocks(this)
to initialize these mocks and inject them (JUnit 4).
With JUnit 5, you must use @ExtendWith(MockitoExtension.class)
.
@RunWith(MockitoJUnitRunner.class) // JUnit 4// @ExtendWith(MockitoExtension.class) for JUnit 5public class SomeManagerTest { @InjectMocks private SomeManager someManager; @Mock private SomeDependency someDependency; // this will be injected into someManager // tests...}
This is a sample code on how @Mock
and @InjectMocks
works.
Say we have Game
and Player
class.
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; }}
As you see, Game
class need Player
to perform an 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 will mock a Player class and it's behaviour using when
and thenReturn
method. Lastly, using @InjectMocks
Mockito will put that Player
into Game
.
Notice that you don't even have to create a new Game
object. Mockito will inject it for you.
// you don't have to do thisGame game = new Game(player);
We will also get same behaviour using @Spy
annotation. Even if the attribute name is different.
@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(); } // ...
That's because Mockito will check the Type Signature
of Game class, which is Player
and List<String>
.
In your test class, the tested class should be annotated with @InjectMocks
. This tells Mockito which class to inject mocks into:
@InjectMocksprivate SomeManager someManager;
From then on, we can specify which specific methods or objects inside the class, in this case, SomeManager
, will be substituted with mocks:
@Mockprivate SomeDependency someDependency;
In this example, SomeDependency
inside the SomeManager
class will be mocked.