304 votes

Injection de mocks Mockito dans un bean Spring

Je voudrais injecter un objet fantaisie Mockito dans un bean Spring (3+) pour effectuer des tests unitaires avec JUnit. Les dépendances de mon bean sont actuellement injectées à l'aide de la fonction @Autowired sur les champs membres privés.

J'ai envisagé d'utiliser ReflectionTestUtils.setField mais l'instance du haricot que je souhaite injecter est en fait un proxy et ne déclare donc pas les champs membres privés de la classe cible. Je ne souhaite pas créer un setter public pour la dépendance car je modifierai alors mon interface uniquement à des fins de test.

J'ai suivi quelques conseils donnée par la communauté Spring mais le mock n'est pas créé et le câblage automatique é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 la suivante :

...
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 je règle le constructor-arg à quelque chose d'invalide, aucune erreur ne se produit lors du démarrage du contexte de l'application.

4 votes

Jetez un coup d'œil à cette toute petite créature : bitbucket.org/kubek2k/springockito/wiki/Home

0 votes

C'est une approche très propre - j'aime ça !

2 votes

Tu m'as eu à Springockito-annotations.

134voto

amra Points 4967

Le meilleur moyen est :

<bean id="dao" class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.package.Dao" /> 
</bean> 

Mise à jour
Dans le fichier de contexte, ce mock doit être listé avant que tout champ autoguidé qui en dépend soit déclaré.

0 votes

J'obtiens une erreur : "Erreur lors de la création d'un bean avec le nom 'mockito' : la définition du bean est abstraite".

4 votes

@amra : spring ne déduit pas le type de l'objet retourné dans ce cas... stackoverflow.com/q/6976421/306488

7 votes

Je ne sais pas pourquoi cette réponse a été autant upvoted, le haricot résultant ne peut pas être autowired parce qu'il a le mauvais type.

117voto

Greg Beauchamp Points 271
@InjectMocks
private MyTestObject testObject;

@Mock
private MyDependentObject mockedObject;

@Before
public void setup() {
        MockitoAnnotations.initMocks(this);
}

Cela injectera tous les objets simulés dans la classe de test. Dans ce cas, il injectera mockedObject dans testObject. Ceci a été mentionné ci-dessus mais voici le code.

1 votes

Comment puis-je bloquer une méthode particulière de mockedObject ?

0 votes

@Teinacher when(mockedObject.execute).thenReturn(objToReturn) ; Vous pouvez mettre cela soit dans la méthode before, soit dans votre méthode de test.

47 votes

FYI : Cette approche ne fonctionnera pas, si je veux un Autowiring partiel et un mocking partiel dans MyTestObject.

81voto

kubek2k Points 1110

Jetez un coup d'œil à cette toute petite créature : https://bitbucket.org/kubek2k/springockito/wiki/Home

65voto

Piotr Gwiazda Points 5208

J'ai une solution très simple utilisant Spring Java Config et Mockito :

@Configuration
public class TestConfig {

    @Mock BeanA beanA;
    @Mock BeanB beanB;

    public TestConfig() {
        MockitoAnnotations.initMocks(this); //This is a key
    }

    //You basically generate getters and add @Bean annotation everywhere
    @Bean
    public BeanA getBeanA() {
        return beanA;
    }

    @Bean
    public BeanB getBeanB() {
        return beanB;
    }
}

0 votes

Merci Piotr ! Cela fonctionne à merveille - tu mérites 10 000 votes positifs pour cela, et je suis sûr qu'ils chanteront des chansons sur toi au paradis.

5 votes

Pour une raison quelconque, avec cette approche, Spring essaie de créer le bean réel de toute façon (au lieu du mock) et s'étouffe sur ce point... Qu'est-ce que je fais mal ?

1 votes

J'ai le même problème

20voto

Doug Moscrop Points 2313

Depuis 1.8.3 Mockito a @InjectMocks - c'est incroyablement utile. Mes tests JUnit sont @RunWith le site MockitoJUnitRunner et je construis @Mock qui satisfont à toutes les dépendances de la classe testée, qui sont toutes injectées lorsque le membre privé est annoté avec le symbole @InjectMocks .

I @RunWith le site SpringJUnit4Runner pour les tests d'intégration seulement maintenant.

Je noterai qu'il ne semble pas être en mesure d'injecter List<T> de la même manière qu'au printemps. Il recherche uniquement un objet Mock qui satisfait à l'exigence de la norme List et n'injectera pas une liste d'objets Mock. La solution de contournement pour moi était d'utiliser un objet @Spy contre une liste instanciée manuellement, et ajouter manuellement le ou les objets fantaisie à cette liste pour les tests unitaires. Peut-être que c'était intentionnel, parce que cela m'a certainement forcé à faire très attention à ce qui était simulé ensemble.

0 votes

Oui, c'est la meilleure solution. Springockito n'injecte pas réellement les mocks pour une raison quelconque dans mon cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X