J'utilise les annotations @Mock
et @InjectMocks
de Mockito pour injecter des dépendances dans des champs privés annotés avec le @Autowired
de Spring:
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Mock
private SomeService service;
@InjectMocks
private Demo demo;
/* ... */
}
et
public class Demo {
@Autowired
private SomeService service;
/* ... */
}
Maintenant, je voudrais également injecter des objets réels dans des champs privés @Autowired
(sans les paramètres). Est-ce possible ou le mécanisme est-il limité à l'injection de Mock?
Utiliser l'annotation @Spy
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Spy
private SomeService service = new RealServiceImpl();
@InjectMocks
private Demo demo;
/* ... */
}
Mockito considérera tous les champs portant l'annotation @Mock
ou @Spy
comme candidats potentiels à injecter dans l'instance annotée avec l'annotation @InjectMocks
. Dans le cas ci-dessus, l'instance 'RealServiceImpl'
sera injectée dans la 'démo'
Pour plus de détails se référer
En plus de la réponse @Dev Blanked, si vous souhaitez utiliser un bean existant créé par Spring, le code peut être modifié pour:
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Inject
private ApplicationContext ctx;
@Spy
private SomeService service;
@InjectMocks
private Demo demo;
@Before
public void setUp(){
service = ctx.getBean(SomeService.class);
}
/* ... */
}
De cette façon, vous n'avez pas besoin de changer votre code (ajouter un autre constructeur) simplement pour que les tests fonctionnent.
Mockito n'est pas un framework DI et même les frameworks DI encouragent les injections de constructeur par rapport aux injections sur le terrain.
Vous venez donc de déclarer à un constructeur de définir les dépendances de la classe sous test:
@Mock
private SomeService serviceMock;
private Demo demo;
/* ... */
@BeforeEach
public void beforeEach(){
demo = new Demo(serviceMock);
}
Utiliser Mockito spy
pour le cas général est un très mauvais conseil. Cela rend la classe de test fragile, non linéaire et sujette aux erreurs: de quoi se moque-t-on réellement? Qu'est-ce qui est vraiment testé?@InjectMocks
et @Spy
nuisent également à la conception dans son ensemble, car ils encouragent les classes surchargées et les responsabilités mixtes dans les classes.
S'il vous plaît lisez la spy()
javadoc avant de l'utiliser à l'aveuglette (les italiques ne m'appartiennent pas):
Crée un espion de l'objet réel. L'espion appelle les méthodes réelles à moins qu'elles ne soient écrites. Les vrais espions doivent être utilisés avec précaution et occasionnellement , par exemple pour traiter du code hérité.
Comme d'habitude, vous allez lire le
partial mock warning
: La programmation orientée objet s'attaque à la complexité en la divisant en objets SRPy distincts et spécifiques. Comment la maquette partielle s'inscrit-elle dans ce paradigme? Eh bien, ça ne veut tout simplement pas ... Une simulation partielle signifie généralement que la complexité a été déplacée vers une méthode différente sur le même objet. Dans la plupart des cas, ce n'est pas comme cela que vous voulez concevoir votre application.Cependant, il existe de rares cas où des simulacres partiels sont utiles: vous ne pouvez pas modifier facilement le code (interfaces tierces, refactoring provisoire du code hérité, etc.). Cependant, je n'utiliserais pas de simulacres partiels pour de code conçu.