La réponse courte est que dans votre exemple, le résultat de mock.method()sera une valeur vide appropriée au type; mockito utilise l'indirection via le proxy, l'interception de méthode et une instance partagée de la MockingProgressclasse afin de déterminer si une invocation d'une méthode sur une maquette est pour le stubbing ou la relecture d'un comportement stubbed existant plutôt que de transmettre des informations sur le stubbing via la valeur de retour de une méthode moquée.
Une mini-analyse en quelques minutes en regardant le code mockito est la suivante. Notez qu'il s'agit d'une description très approximative - il y a beaucoup de détails en jeu ici. Je vous suggère de vérifier vous-même la source sur github .
Tout d'abord, lorsque vous vous moquez d'une classe en utilisant la mockméthode de la Mockitoclasse, c'est essentiellement ce qui se passe:
Mockito.mockdélègue à org.mockito.internal.MockitoCore.mock, en passant les paramètres de simulation par défaut en tant que paramètre.
MockitoCore.mockdélègue à org.mockito.internal.util.MockUtil.createMock
- La
MockUtilclasse utilise la ClassPathLoaderclasse pour obtenir une instance de MockMakerà utiliser pour créer la maquette. Par défaut, la classe CgLibMockMaker est utilisée.
CgLibMockMakerutilise une classe empruntée à JMock, ClassImposterizerqui gère la création de la maquette. Les éléments clés de la «magie mockito» utilisés sont ceux MethodInterceptorutilisés pour créer le simulacre: le mockito MethodInterceptorFilter, et une chaîne d'instances MockHandler, y compris une instance de MockHandlerImpl . L'intercepteur de méthode passe les appels à l'instance MockHandlerImpl, qui implémente la logique métier à appliquer lorsqu'une méthode est invoquée sur un simulacre (c'est-à-dire, en cherchant à voir si une réponse est déjà enregistrée, en déterminant si l'appel représente un nouveau stub, etc. L'état par défaut est que si un stub n'est pas déjà inscrit pour la méthode appelée, une valeur vide appropriée au type est renvoyée.
Maintenant, regardons le code dans votre exemple:
when(mock.method()).thenReturn(someValue)
Voici l'ordre dans lequel ce code s'exécutera:
mock.method()
when(<result of step 1>)
<result of step 2>.thenReturn
La clé pour comprendre ce qui se passe est ce qui se passe lorsque la méthode sur la maquette est appelée: l'intercepteur de méthode reçoit des informations sur l'appel de méthode et les délègue à sa chaîne d' MockHandlerinstances, qui finit par déléguer à MockHandlerImpl#handle. Pendant MockHandlerImpl#handle, le gestionnaire de simulation crée une instance de OngoingStubbingImplet la transmet à l' MockingProgressinstance partagée .
Lorsque la whenméthode est appelée après l'appel de method(), elle délègue à MockitoCore.when, qui appelle la stub()méthode de la même classe. Cette méthode décompresse le stubbing en cours de l' MockingProgressinstance partagée dans laquelle l' method()appel simulé a écrit et la renvoie. Ensuite, la thenReturnméthode est appelée sur l' OngoingStubbinginstance.