L'injection de Mockito se moque d'une source de haricot
Je voudrais injecter un Mockito maquette d'un objet dans un Ressort (3+) de haricots pour les fins de tests unitaires avec JUnit. Mon haricot dépendances sont actuellement injectée à l'aide de la @Autowired
annotation privé, membre de champs.
J'ai pensé à utiliser ReflectionTestUtils.setField
mais l'exemple d'haricot que je tiens à injecter est en fait un proxy et donc de ne pas déclarer le privé, les champs des membres de la classe cible. Je ne souhaite pas créer un public setter de la dépendance que je vais modifier mon interface est purement à des fins de test.
J'ai suivi quelques conseils donné par le Printemps de la communauté, mais la maquette est pas créé et l'auto-câblage échoue:
<bean id="dao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.package.Dao" />
</bean>
L'erreur que je rencontre actuellement est comme suit:
...
Caused by: org...NoSuchBeanDefinitionException:
No matching bean of type [com.package.Dao] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {
@org...Autowired(required=true),
@org...Qualifier(value=dao)
}
at org...DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(D...y.java:901)
at org...DefaultListableBeanFactory.doResolveDependency(D...y.java:770)
Si j'ai mis le constructor-arg
de la valeur à quelque chose non valide aucune erreur ne se produit lors du démarrage de l'application de contexte.
- Veuillez jeter un oeil à cette petite créature: bitbucket.org/kubek2k/springockito/wiki/Home
- C'est très propre approche - je l'aime!
- Vous m'avez eu à Springockito-annotations.
- Oubliez tout le reste,
springockito-annotations
est quelque chose que vous souhaitez utiliser. La bonne chose est que vous pouvez avoir un non-complet de configuration XML (omettre les simulacres) et les annotations va remplir les blancs (les simulacres). Puis juste@Autowire
tout. - Malheureusement, Springockito ne vous laisse pas saisir facilement le
WebApplicationContext
(vous pouvez le faire si vous êtes en train de rédiger un test d'intégration avec@WebAppConfiguation
), tel que documenté par tihs question: bitbucket.org/kubek2k/springockito/issue/12/... Vous avez probablement juste eu à appeler lemock()
méthode vous-même. - Méfiez-vous de bitbucket.org/kubek2k/springockito/issue/37/...
- Pour ceux qui utilisent le ressort 4.*, à compter de janvier 2015, cela ne semble pas fonctionner avec la dernière version du printemps mockito version et le projet semble être inactif.
- vos liens sont cassés.. pourriez vous s'il vous plaît mettre à jour?
Vous devez vous connecter pour publier un commentaire.
La meilleure façon est:
Mise à jour
Dans le contexte d'un fichier cette maquette doit figurer avant toute autocâblés champ selon elle est déclarée.
Ce qui permettra d'injecter tout se moquaient d'objets dans la classe de test. Dans ce cas, il va injecter mockedObject dans le testObject. Cela a été mentionné ci-dessus, mais voici le code.
mockedObject
?Mockito.spy(...)
sur cemockedObject
à la place? Et puis utiliserwhen(mockedObject.execute).thenReturn(objToReturn)
oudoReturn(objToReturn).when(mockedObject).execute()
. Deuxième, de ne pas invoquer la vraie méthode. Vous pouvez vérifier aussiMockito.doCallRealMethod()
documentationJ'ai une solution très simple à l'aide de Spring Java Config et Mockito:
@Primary
lors de la déclaration de fantaisie beaninitMocks
? Pourquoi ne pas simplementreturn Mockito.mock(BeanA.class)
dansgetBeanA
? De cette manière, il est plus simple et il y a moins de code. Ce qui me manque?Donné:
Vous pouvez avoir la classe qui est en train d'être testé chargé par permettra à l'autowiring, se moquer de la dépendance avec Mockito, et ensuite utiliser le Printemps ReflectionTestUtils à injecter de la fantaisie dans la classe testée.
Veuillez noter qu'avant le Printemps 4.3.1, cette méthode ne fonctionne pas avec les services de derrière un proxy (annoté avec
@Transactional
, ouCacheable
, par exemple). Ce problème a été résolu par SPR-14050.Pour les versions antérieures, une solution consiste à déballer le proxy, comme décrit ici: Transactionnelle annotation évite services être moqué (qui est ce que
ReflectionTestUtils.setField
n'maintenant par défaut)Si vous êtes à l'aide de Spring Boot 1.4, il dispose d'un fantastique moyen de le faire. Suffit d'utiliser la nouvelle marque
@SpringBootTest
sur votre classe et@MockBean
sur le terrain et au Printemps Démarrage, créer une maquette de ce type et il va l'injecter dans le contexte (au lieu d'injecter de l'original):D'autre part, si vous n'êtes pas à l'aide de Printemps de Démarrage ou vous utilisez une version antérieure, vous devrez faire un peu plus de travail:
Créer un
@Configuration
bean qui injecte de votre se moque de Printemps contexte:À l'aide de
@Primary
annotation que vous avez dit au printemps, que ce bean a priorité si aucun qualificatif n'est spécifiée.Assurez-vous d'annoter la classe avec
@Profile("useMocks")
afin de contrôler les classes de l'utilisation de la maquette et ceux qui vont utiliser le réel bean.Enfin, dans votre test, activer
userMocks
profil:Si vous ne souhaitez pas utiliser la maquette mais le véritable haricot, il suffit de ne pas activer
useMocks
profil:web.xml
et AnnotationConfigWebApplicationContext de l'installation. A utiliser@WebAppConfiguration
au lieu de@WebIntegrationTest
et@ContextHierarchy
avec@ContextConfiguration
au lieu de@SpringApplicationConfiguration
.Depuis 1.8.3 Mockito a @InjectMocks - ce est incroyablement utile. Mon JUnit tests sont annotation @RunWith la MockitoJUnitRunner et je de construire @Mock les objets qui satisfont à toutes les dépendances de la classe testée, qui sont tous injecté lorsque le membre privé est annotée avec @InjectMocks.
Je annotation @RunWith la SpringJUnit4Runner pour les tests d'intégration seulement maintenant.
Je note qu'il ne semble pas être en mesure d'injecter de la Liste de la même manière que le Printemps. Il semble que pour un objet Fantaisie qui satisfait à la Liste, et de ne pas injecter une liste d'objets Fantaisie. La solution pour moi a été d'utiliser un @Espionner un manuellement instancié liste, et manuellement .ajouter le simulacre de l'objet(s) à cette liste pour les tests unitaires. Peut-être que c'était intentionnel, parce que, certainement, cela m'a obligé à payer une attention particulière à ce qui était moqué d'ensemble.
Mise à jour: Il y a mieux maintenant, plus propres solutions à ce problème. Veuillez prendre en compte les autres réponses d'abord.
J'ai finalement trouvé une réponse à cette par ronen sur son blog. Le problème que j'ai est due à la méthode
Mockito.mock(Class c)
déclarer un type de retour deObject
. Par conséquent, le Printemps est dans l'impossibilité de déduire le type de bean à partir de la méthode de type de retour.Ronen de la solution est de créer un
FactoryBean
de mise en œuvre qui renvoie des simulacres. LeFactoryBean
interface permet de Printemps à la requête du type des objets créés par l'usine bean.Mon moqué de haricot définition ressemble maintenant à:
Dès le Printemps 3.2, ce n'est plus un problème. Le printemps prend désormais en charge permettra à l'autowiring des résultats de générique de méthodes de fabrique. Voir la section intitulée "Générique de Méthodes de Fabrique" de ce blog: http://spring.io/blog/2012/11/07/spring-framework-3-2-rc1-new-testing-features/.
Le point clé est:
Qui signifie que cela doit fonctionner hors de la boîte:
Code ci-dessous fonctionne avec permettra à l'autowiring - ce n'est pas la version la plus courte mais utile quand il doit travailler uniquement avec la norme printemps/mockito pots.
Si vous utilisez printemps >= 3.0, essayez d'utiliser des Ressorts
@Configuration
annotation à définir une partie du contexte de l'applicationSi vous ne voulez pas utiliser le @ImportResource, il peut être fait dans l'autre sens aussi:
Pour plus d'informations, jetez un oeil au printemps-cadre de référence : Java configuration du conteneur
Peut-être pas la solution idéale, mais j'ai tendance à ne pas utiliser le printemps à ne DI pour les tests unitaires. les dépendances pour un seul haricot (la classe sous test) ne sont pas habituellement trop complexe donc, je viens de faire l'injection directement dans le code de test.
Je pouvez effectuer les opérations suivantes à l'aide de Mockito:
Affichant quelques exemples basés sur des approches décrites ci-dessus
Avec Le Printemps:
Sans Ressort:
Mise à jour - nouvelle réponse ici: https://stackoverflow.com/a/19454282/411229. Cette réponse ne s'applique qu'à ceux du Printemps versions 3.2.
J'ai cherché un moment pour une solution définitive à cette. Ce blog semble couvrir tous mes besoins, et ne pas compter sur la commande de haricot déclarations. Tout le crédit à Mattias Severson. http://www.jayway.com/2011/11/30/spring-integration-tests-part-i-creating-mock-objects/
Fondamentalement, mettre en œuvre une interface factorybean
Prochaine mise à jour de votre printemps config avec les éléments suivants:
Regardant Springockito rythme de développement et nombre de questions en suspens, je voudrais être peu inquiet à l'introduire dans ma suite de test de pile aujourd'hui. Fait que la dernière version a été fait avant le Printemps 4 version apporte des questions comme "Est-il possible d'intégrer facilement avec Ressort 4?". Je ne sais pas, parce que je ne l'ai pas essayé. Je préfère la pureté du Printemps approche, si j'ai besoin de se moquer de Printemps bean dans le test d'intégration.
Il y a une option pour de faux Printemps de haricots avec de simples Printemps fonctionnalités. Vous avez besoin d'utiliser
@Primary
,@Profile
et@ActiveProfiles
annotations pour elle. J'ai écrit un billet de blog sur le sujet.J'ai trouvé une semblable réponse teabot pour créer un MockFactory qui fournit les simulacres. J'ai utilisé l'exemple suivant pour créer la maquette de l'usine (depuis le lien pour narkisr sont morts):
http://hg.randompage.org/java/src/407e78aa08a0/projects/bookmarking/backend/spring/src/test/java/org/randompage/bookmarking/backend/testUtils/MocksFactory.java
Cela aide également à empêcher que le Printemps veut résoudre les injections de la moqué de haricot.
ce ^ fonctionne parfaitement bien si déclarée d'abord/au début du fichier XML. Mockito 1.9.0/Printemps 3.0.5
- Je utiliser une combinaison de l'approche utilisée dans les réponses par Markus T et un simple helper mise en œuvre de
ImportBeanDefinitionRegistrar
qui ressemble pour une mesure d'annotation (@MockedBeans
) dans lequel on peut spécifier les classes sont se moque de lui. Je crois que cette approche aboutit à une description concise de l'unité de test avec certains du code réutilisable liées à moqueur supprimé.Voici comment un échantillon de test de l'unité regarde avec cette approche: les
Pour ce faire, vous devez définir deux classes d'aide - annotations personnalisées (
@MockedBeans
) et personnaliséImportBeanDefinitionRegistrar
mise en œuvre.@MockedBeans
annotation définition doit être annotée avec@Import(CustomImportBeanDefinitionRegistrar.class)
et laImportBeanDefinitionRgistrar
besoin d'ajouter de la moqué de haricots définitions de la configuration duregisterBeanDefinitions
méthode.Si vous aimez l'approche que vous pouvez trouver un exemple de implémentations sur mon article sur le blog.
J'ai développé une solution basée sur la proposition de Kresimir Nesek. J'ai ajouté une nouvelle annotation @EnableMockedBean afin de rendre le code un peu plus propre et modulaire.
J'ai écrit un post l'expliquer.
Je vous propose de migrer votre projet pour le Printemps de Démarrage 1.4. Après cela, vous pouvez utiliser la nouvelle annotation
@MockBean
de truquer votrecom.package.Dao
Aujourd'hui j'ai découvert que le printemps contexte où j'ai déclaré avant de la Mockito haricots, n'était pas à la charge.
Après le déplacement de la APRÈS la on se moque, le contexte de l'application a été chargé avec succès.
Prendre soin 🙂
Pour l'enregistrement, tous mes tests de fonctionner correctement par juste faire de l'appareil paresseux-initialisé, par exemple:
Je suppose que la raison en est l'un Mattias explique ici (en bas du post), qu'une solution de contournement est de changer l'ordre les haricots sont déclarées - initialisation différée est "une sorte de" avoir l'appareil a déclaré à la fin.
Si vous utilisez le Contrôleur d'Injection, assurez-vous que vos variables locales ne sont PAS "finale"