J'utilise Mockito @Mock
et des @InjectMocks
annotations pour injecter des dépendances dans des champs privés qui sont annotés avec Spring @Autowired
:
@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 @Autowired
champs privés (sans setters). Est-ce possible ou le mécanisme est-il limité à l'injection de Mocks uniquement?
MockitoAnnotations.initMocks(this);
la@Before
méthode. Je sais que ce n'est pas directement lié à la question d'origine, mais à quiconque viendrait plus tard, cela devrait être ajouté pour rendre cela exécutable.@RunWith(MockitoJUnitRunner.class)
), vous n'avez pas besoin de la ligneMockitoAnnotations.initMocks(this);
Réponses:
Utiliser l'
@Spy
annotation@RunWith(MockitoJUnitRunner.class) public class DemoTest { @Spy private SomeService service = new RealServiceImpl(); @InjectMocks private Demo demo; /* ... */ }
Mockito considérera tous les champs ayant
@Mock
une@Spy
annotation comme des candidats potentiels à injecter dans l'instance annotée avec@InjectMocks
annotation. Dans le cas ci-dessus, l''RealServiceImpl'
instance sera injectée dans la `` démo ''Pour plus de détails, reportez-vous
Mockito-maison
@Espion
@Moquer
la source
Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types
new RealServiceImpl()
,@Spy private SomeService service;
crée un objet réel en utilisant le constructeur par défaut avant de l'espionner de toute façon.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) juste pour que les tests fonctionnent.
la source
Autowired
champs des dépendances étaient créés correctement.Mockito n'est pas un framework DI et même les frameworks DI encouragent les injections de constructeur par rapport aux injections de champ.
Vous déclarez donc simplement un constructeur pour définir les dépendances de la classe testée:
@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 terrible conseil. Cela rend la classe de test fragile, pas droite et sujette aux erreurs: qu'est-ce qui est vraiment moqué? Qu'est-ce qui est vraiment testé?@InjectMocks
et@Spy
nuit également à la conception globale car elle encourage les classes gonflées et les responsabilités mixtes dans les classes.Veuillez lire le
spy()
javadoc avant de l'utiliser à l'aveugle (l'accent n'est pas le mien):la source
@MockBean
)Au printemps, il existe un utilitaire dédié appelé
ReflectionTestUtils
à cet effet. Prenez l'exemple spécifique et injectez dans le champ.@Spy .. @Mock .. @InjectMock Foo foo; @BeforeEach void _before(){ ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field }
la source
Je sais que c'est une vieille question, mais nous avons été confrontés au même problème en essayant d'injecter des chaînes. Nous avons donc inventé une extension JUnit5 / Mockito qui fait exactement ce que vous voulez: https://github.com/exabrial/mockito-object-injection
ÉDITER:
@InjectionMap private Map<String, Object> injectionMap = new HashMap<>(); @BeforeEach public void beforeEach() throws Exception { injectionMap.put("securityEnabled", Boolean.TRUE); } @AfterEach public void afterEach() throws Exception { injectionMap.clear(); }
la source