Existe-t-il un moyen, en utilisant Mockito, de se moquer de certaines méthodes dans une classe, mais pas d'autres?
Par exemple, dans ce ( il est vrai pièce ) Stock
classe je veux railler les getPrice()
et les getQuantity()
valeurs retour (comme indiqué dans l'extrait de test ci - dessous) , mais je veux que le getValue()
pour effectuer la multiplication comme code dans la Stock
classe
public class Stock {
private final double price;
private final int quantity;
Stock(double price, int quantity) {
this.price = price;
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getValue() {
return getPrice() * getQuantity();
}
@Test
public void getValueTest() {
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
double value = stock.getValue();
// Unfortunately the following assert fails, because the mock Stock getValue() method does not perform the Stock.getValue() calculation code.
assertEquals("Stock value not correct", 100.00*200, value, .00001);
}
Réponses:
Pour répondre directement à votre question, oui, vous pouvez vous moquer de certaines méthodes sans en moquer d'autres. C'est ce qu'on appelle une simulation partielle . Voir la documentation Mockito sur les simulations partielles pour plus d'informations.
Pour votre exemple, vous pouvez faire quelque chose comme ceci dans votre test:
Dans ce cas, chaque implémentation de méthode est simulée, sauf indication contraire
thenCallRealMethod()
dans lawhen(..)
clause.Il y a aussi une possibilité dans l'autre sens avec espion au lieu de se moquer :
Dans ce cas, toutes les implémentations de méthodes sont les vraies, sauf si vous avez défini un comportement simulé avec
when(..)
.Il y a un écueil important lorsque vous utilisez
when(Object)
avec espion comme dans l'exemple précédent. La vraie méthode sera appelée (car ellestock.getPrice()
est évaluée avantwhen(..)
lors de l'exécution). Cela peut être un problème si votre méthode contient une logique qui ne doit pas être appelée. Vous pouvez écrire l'exemple précédent comme ceci:Une autre possibilité peut être d'utiliser
org.mockito.Mockito.CALLS_REAL_METHODS
, comme:Cela délègue des appels sans entrave à des implémentations réelles.
Cependant, avec votre exemple, je crois que ce sera toujours pas, depuis la mise en œuvre
getValue()
repose surquantity
etprice
, plutôt quegetQuantity()
etgetPrice()
, ce dont vous vous êtes moqué.Une autre possibilité consiste à éviter complètement les moqueries:
la source
Stock stock = spy(Stock.class);
Cela semble faux, laspy
méthode semble accepter uniquement les objets et non les classes.doReturn(retval).when(spyObj).methodName(args)
etwhen(spyObj.methodName(args)).thenReturn(retval)
La moquerie partielle d'une classe est également prise en charge via Spy in mockito
Consultez les documents
1.10.19
et2.7.22
pour une explication détaillée.la source
Selon les documents :
la source
class NaughtyLinkedList extends LinkedList { public int size() { throw new RuntimeException("don't call me");} } @Test public void partialMockNaughtLinkedList(){ List mock = mock(NaughtyLinkedList.class, CALLS_REAL_METHODS); mock.add(new Object()); // this calls the real function when(mock.size()).thenReturn(2); // For whatever reason, this lines throws the RuntimeException. assertEquals(2,mock.size()); }
Ça ne marche pas. Pour quelque raison que ce soit, quand "quand" est exécuté, il exécute en fait la méthode qui est censée se moquer. Code:Ce que vous voulez, c'est
org.mockito.Mockito.CALLS_REAL_METHODS
selon les documents:Ainsi, votre code devrait ressembler à:
L'appel aux
Stock stock = mock(Stock.class);
appelsorg.mockito.Mockito.mock(Class<T>)
qui ressemble à ceci:Les documents de la valeur
RETURNS_DEFAULTS
indiquent:la source
withSettings()...
comme ça? Il semble queorg.mockito.internal.stubbing.answers.CallsRealMethods()
(par exemple) pourrait faire le travail ... et le javadoc pour cette classe indique spécifiquement qu'il est destiné à être utilisé pour les moqueries partielles ...thenReturn
- dire qu'il exécutera réellement la méthode (ce qui pourrait causer des problèmes, mais pas dans cet exemple), etdoReturn
est donc préférable dans un tel cas ...?La moquerie partielle utilisant la méthode d'espionnage de Mockito pourrait être la solution à votre problème, comme déjà indiqué dans les réponses ci-dessus. Dans une certaine mesure, je conviens que, pour votre cas d'utilisation concret, il peut être plus approprié de se moquer de la recherche de base de données. D'après mon expérience, cela n'est pas toujours possible - du moins pas sans autres solutions de contournement - que je considérerais comme très lourd ou du moins fragile. Notez que le mocking partiel ne fonctionne pas avec les versions alliées de Mockito. Vous avez utilisé au moins 1.8.0.
J'aurais juste écrit un simple commentaire pour la question d'origine au lieu de poster cette réponse, mais StackOverflow ne le permet pas.
Encore une chose: je ne peux vraiment pas comprendre que plusieurs fois une question posée ici obtient un commentaire avec "Pourquoi vous voulez faire cela" sans au moins essayer de comprendre le problème. Surtout quand il s'agit de besoin de moqueries partielles, il y a vraiment beaucoup de cas d'utilisation que je pourrais imaginer où cela serait utile. C'est pourquoi les gars de Mockito ont fourni cette fonctionnalité. Cette fonctionnalité ne doit bien sûr pas être surutilisée. Mais lorsque nous parlons de configurations de cas de test qui autrement ne pourraient pas être établies de manière très compliquée, l'espionnage devrait être utilisé.
la source