java - Diferencia entre @Mock y @InjectMocks
mockito injectmocks (9)
¿Cuál es la diferencia entre @Mock
y @InjectMocks
en el marco de Mockito?
En su clase de prueba, la clase probada debe anotarse con @InjectMocks. Esto le dice a Mockito en qué clase inyectar simulacros en:
@InjectMocks
private SomeManager someManager;
A partir de entonces, podemos especificar qué métodos u objetos específicos dentro de la clase, en este caso SomeManager , serán sustituidos por simulacros:
@Mock
private SomeDependency someDependency;
En este ejemplo, se burlará de algunas dependencias dentro de la clase SomeManager.
Este es un código de ejemplo sobre cómo funcionan @Mock
y @InjectMocks
.
Digamos que tenemos clase de Game
y 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;
}
}
Como ves, la clase Game
necesita que el Player
realice 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 de jugador y su comportamiento usa el método thenReturn
y thenReturn
. Por último, el uso de @InjectMocks
Mockito pondrá a ese Player
en el Game
.
Tenga en cuenta que ni siquiera tiene que crear un new Game
objeto de new Game
. Mockito te lo inyectará.
// you don''t have to do this
Game game = new Game(player);
También obtendremos el mismo comportamiento utilizando la anotación @Spy
. 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
de juego, que es Player
y List<String>
.
Muchas personas han dado una gran explicación aquí sobre @Mock
vs @InjectMocks
. Me gusta, pero creo que nuestras pruebas y aplicaciones deben escribirse de tal manera que no debamos usar @InjectMocks
.
Referencia para una lectura adicional con ejemplos: tedvinke.wordpress.com/2014/02/13/…
Tenga en cuenta que @InjectMocks
están a punto de ser deprecated
dejar de usar @InjectMocks y programar su eliminación en Mockito 3/4
y puedes seguir la respuesta y el enlace de @avp en:
¿Por qué no debería usar la anotación de InjectMocks en los campos de Autowire?
Un "marco burlón", en el que se basa Mockito, es un marco que le brinda la capacidad de crear objetos simulados (en términos antiguos, estos objetos podrían denominarse derivaciones, ya que funcionan como derivaciones para la funcionalidad dependiente) En otras palabras, una simulación el objeto se utiliza para imitar el objeto real del que depende el código, usted crea un objeto proxy con el marco de burla. Al utilizar objetos simulados en sus pruebas, esencialmente va de las pruebas unitarias normales a las pruebas integracionales.
Mockito es un marco de prueba de código abierto para Java lanzado bajo la Licencia MIT, es un "marco burlón", que le permite escribir pruebas hermosas con API limpia y simple. Existen muchos marcos de simulacros diferentes en el espacio de Java, sin embargo, existen esencialmente dos tipos principales de marcos de objetos simulados, los que se implementan mediante proxy y los que se implementan a través de la reasignación de clases.
Los marcos de inyección de dependencia como Spring le permiten inyectar sus objetos proxy sin modificar ningún código, el objeto simulado espera que se llame a un determinado método y devolverá un resultado esperado.
La anotación @InjectMocks
intenta crear una instancia de la instancia del objeto de prueba e inyecta los campos anotados con @Mock
o @Spy
en los campos privados del objeto de prueba.
MockitoAnnotations.initMocks(this)
llama, restablece el objeto de prueba y reinicia los simulacros, así que recuerde tener esto en su anotación @Before
/ @BeforeMethod
.
Una de las ventajas que obtiene con el enfoque mencionado por @Tom es que no tiene que crear ningún constructor en el SomeManager, y por lo tanto limitar a los clientes para que lo ejemplifiquen.
@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...
}
Si es una buena práctica o no, depende del diseño de su aplicación.
@Mock
anotación se burla del objeto en cuestión.
@InjectMocks
anotación @InjectMocks
permite inyectar en el objeto subyacente las @Mock
diferentes (y relevantes) creadas por @Mock
.
Ambos son complementarios.
@Mock
crea un simulacro. @InjectMocks
crea una instancia de la clase e inyecta las simulaciones que se crean con las @Mock
(o @Spy
) en esta instancia.
Tenga en cuenta que debe usar @RunWith(MockitoJUnitRunner.class)
o Mockito.initMocks(this)
para inicializar estos simulacros e inyectarlos.
@RunWith(MockitoJUnitRunner.class)
public class SomeManagerTest {
@InjectMocks
private SomeManager someManager;
@Mock
private SomeDependency someDependency; // this will be injected into someManager
//tests...
}
- @Mock crea una implementación simulada para las clases que necesita.
- @InjectMock crea una instancia de la clase e inyecta los simulacros que están marcados con las anotaciones @Mock en ella.
Por ejemplo
@Mock
StudentDao studentDao;
@InjectMocks
StudentService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
Aquí necesitamos la clase dao para la clase de servicio. Por lo tanto, nos burlamos y lo inyectamos en la instancia de clase de servicio. De manera similar, en Spring Framework todos los frijoles @Autowired se pueden burlar de @Mock en jUnits e inyectarlos en su frijol a través de @InjectMocks.
El método MockitoAnnotations.initMocks (this) inicializa estos simulacros y los inyecta para cada método de prueba, por lo que debe llamarse en el método de configuración.
Este enlace tiene un buen tutorial para el framework Mockito.