Différence entre @Mock et @InjectMocks

Quelle est la différence entre @Mock et @InjectMocks dans le cadre de Mockito?

@Mock crée un simulacre. @InjectMocks crée une instance de la classe et injecte les @Mock créées avec les @Mock (ou @Spy ) dans cette instance. Notez que vous devez utiliser @RunWith(MockitoJUnitRunner.class) ou Mockito.initMocks(this) pour initialiser ces simulacres et les injecter.

 @RunWith(MockitoJUnitRunner.class) public class SomeManagerTest { @InjectMocks private SomeManager someManager; @Mock private SomeDependency someDependency; // this will be injected into someManager //tests... } 

Dans votre classe de test, la classe testée doit être annotée avec @InjectMocks. Cela indique à Mockito quelle classe injecter des objects dans:

 @InjectMocks private SomeManager someManager; 

À partir de là, nous pouvons spécifier les méthodes ou objects spécifiques à l’intérieur de la classe, dans ce cas SomeManager , seront remplacés par des mocks:

 @Mock private SomeDependency someDependency; 

Dans cet exemple, SomeDependency au sein de la classe SomeManager sera simulé.

@Mock annotation @Mock se moque de l’object concerné.

@InjectMocks annotation @InjectMocks permet d’injecter dans l’object sous-jacent les différents (et pertinents) mocks créés par @Mock .

Les deux sont complémentaires.

Ceci est un exemple de code sur le fonctionnement de @Mock et @InjectMocks .

Disons que nous avons la classe Game and Player .

 class Game { private Player player; public Game(Player player) { this.player = player; } public Ssortingng attack() { return "Player attack with: " + player.getWeapon(); } } class Player { private Ssortingng weapon; public Player(Ssortingng weapon) { this.weapon = weapon; } Ssortingng getWeapon() { return weapon; } } 

Comme vous le voyez, la classe Game besoin de Player pour effectuer une 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 simulera une classe Player et son comportement en utilisant la méthode thenReturn et thenReturn . Enfin, en utilisant @InjectMocks Mockito mettra ce Player en Game .

Notez que vous n’avez même pas besoin de créer un new Game object new Game . Mockito l’injectera pour vous.

 // you don't have to do this Game game = new Game(player); 

Nous obtiendrons également le même comportement en utilisant l’annotation @Spy . Même si le nom de l’atsortingbut est différent.

 @RunWith(MockitoJUnitRunner.class) public class GameTest { @Mock Player player; @Spy List 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 opponents; public Game(Player player, List opponents) { this.player = player; this.opponents = opponents; } public int numberOfEnemies() { return opponents.size(); } // ... 

En effet, Mockito vérifie la classe Type Signature of Game, qui est Player et List .

  • @Mock crée une implémentation simulée pour les classes dont vous avez besoin.
  • @InjectMock crée une instance de la classe et y injecte les simulations marquées des annotations @Mock.

Par exemple

 @Mock StudentDao studentDao; @InjectMocks StudentService service; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } 

Ici, nous avons besoin de la classe dao pour la classe de service. On se moque donc de cela et l’injecte dans l’instance de la classe de service. De même, dans le framework Spring, tous les beans @Autowired peuvent être moqués par @Mock dans jUnits et injectés dans votre bean via @InjectMocks.

La méthode MockitoAnnotations.initMocks (this) initialise ces simulations et les injecte pour chaque méthode de test. Elle doit donc être appelée dans la méthode setUp.

Ce lien a un bon tutoriel pour le framework Mockito

Un “cadre moqueur”, sur lequel Mockito est basé, est un framework qui vous permet de créer des objects Mock (en d’autres termes, ces objects peuvent être appelés shunts, car ils fonctionnent comme des shunts pour des fonctionnalités dépendantes). object est utilisé pour imiter l’object réel dont dépend votre code, vous créez un object proxy avec le cadre moqueur. En utilisant des objects fictifs dans vos tests, vous passez essentiellement des tests unitaires normaux aux tests d’intégration.

Mockito est un framework de test open source pour Java publié sous la licence MIT, il s’agit d’un “framework moqueur”, qui vous permet d’écrire de magnifiques tests avec une API simple et propre. Il existe de nombreux frameworks de moquage différents dans l’espace Java, mais il existe essentiellement deux principaux types de structures d’objects simulés, ceux qui sont implémentés via un proxy et ceux qui sont implémentés via le remappage de classes.

Les frameworks d’dependency injections comme Spring vous permettent d’injecter vos objects proxy sans modifier de code, l’object simulé s’attend à ce qu’une certaine méthode soit appelée et elle retournera un résultat attendu.

L’annotation @InjectMocks tente d’instancier l’instance de l’object testing et injecte des champs annotés avec @Mock ou @Spy dans des champs privés de l’object testing.

MockitoAnnotations.initMocks(this) appelle, réinitialise l’object testing et réinitialise les objects @BeforeMethod . N’oubliez pas de l’avoir dans votre annotation @Before / @BeforeMethod .

L’un des avantages de l’approche mentionnée par @Tom est que vous n’avez pas besoin de créer de constructeur dans SomeManager, ce qui limite les clients à l’instancier.

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

Que ce soit une bonne pratique ou non, cela dépend de la conception de votre application.

Beaucoup de gens ont donné une bonne explication à propos de @Mock vs @InjectMocks . Je l’aime bien, mais je pense que nos tests et applications doivent être écrits de manière à ce que nous n’ayons pas besoin d’utiliser @InjectMocks .

Référence pour d’autres lectures avec des exemples: https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/