Diferencia entre @Mock y @InjectMocks
¿ Cuál es la diferencia entre @Mock
y @InjectMocks
en el marco Mockito?
@Mock
crea una burla. @InjectMocks
crea una instancia de la clase e inyecta los simulacros que se crean con las anotaciones @Mock
(o @Spy
) en esta instancia.
Tenga en cuenta que debe utilizar @RunWith(MockitoJUnitRunner.class)
o Mockito.initMocks(this)
para inicializar estos simulacros e inyectarlos (JUnit 4).
Con JUnit 5, debes usar @ExtendWith(MockitoExtension.class)
.
@RunWith(MockitoJUnitRunner.class) // JUnit 4
// @ExtendWith(MockitoExtension.class) for JUnit 5
public class SomeManagerTest {
@InjectMocks
private SomeManager someManager;
@Mock
private SomeDependency someDependency; // this will be injected into someManager
// tests...
}
Este es un código de muestra sobre cómo @Mock
y @InjectMocks
funciona.
Digamos que tenemos Game
y Player
clase.
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;
}
}
Como puede ver, Game
la clase necesita Player
realizar un 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 se burlará de una clase Player y su comportamiento usando when
un thenReturn
método. Por último, usar @InjectMocks
Mockito lo colocará Player
en Game
.
Tenga en cuenta que ni siquiera tiene que crear un new Game
objeto. Mockito lo inyectará por ti.
// you don't have to do this
Game game = new Game(player);
También obtendremos el mismo comportamiento usando @Spy
la anotación. Incluso si el nombre del atributo es diferente.
@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();
}
// ...
Esto se debe a que Mockito verificará la Type Signature
clase Game, que es Player
y List<String>
.