Mockito - Moqueur Classes Concrètes
Donné le code suivant:
LinkedList list = mock(LinkedList.class);
doCallRealMethod().when(list).clear();
list.clear();
par l'exécution de ce test, une NullPointerException est levée à partir de la première ligne dans la LinkedList#claire:
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
//Code omitted.
mais en-tête a été instancié avant:
private transient Entry<E> header = new Entry<E>(null, null, null);
Quelqu'un pourrait-il expliquer ce qui se passe au cours de se moquer de la création?
####### La mise à JOUR. ######
Avoir lu toutes les réponses, surtout Ajay, j'ai regardé dans Objenesis code source et savoir que c'est à l'aide de la Réflexion de l'API pour créer le proxy de l'instance (par CGLIB) et, par conséquent, en contournant tous les constructeurs dans la hiérarchie jusqu'à java.lang.Objet.
Voici un exemple de code pour simuler la question:
public class ReflectionConstructorTest {
@Test
public void testAgain() {
try {
//java.lang.Object default constructor
Constructor javaLangObjectConstructor = Object.class
.getConstructor((Class[]) null);
Constructor mungedConstructor = ReflectionFactory
.getReflectionFactory()
.newConstructorForSerialization(CustomClient.class, javaLangObjectConstructor);
mungedConstructor.setAccessible(true);
//Creates new client instance without calling its constructor
//Thus "name" is not initialized.
Object client = mungedConstructor.newInstance((Object[]) null);
//this will print "CustomClient"
System.out.println(client.getClass());
//this will print "CustomClient: null". name is null.
System.out.println(client.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
}
class CustomClient {
private String name;
CustomClient() {
System.out.println(this.getClass().getSimpleName() + " - Constructor");
this.name = "My Name";
}
@Override
public String toString() {
return this.getClass().getSimpleName() + ": " + name;
}
}
nous montrer plein stacktrace
OriginalL'auteur mhshams | 2013-01-17
Vous devez vous connecter pour publier un commentaire.
Votre raisonnement est sans faille.
La question clé est que vous n'êtes pas d'exploitation sur le
LinkedList
objet. Voici ce qui se passe derrière les coulisses:L'objet qui vous sont donnés par Mockito est
mock()
est un Enhancer objet de la CGLIB bibliothèque.Pour moi, c'est quelque chose comme
java.util.LinkedList$$EnhancerByMockitoWithCGLIB$$cae81a28
le type qui agit comme un Proxy, mais avec les champs aux valeurs par défaut. (null,0, etc)
La raison pour laquelle vous êtes en mesure de se référer à la moqué de l'objet avec une LinkedList référence signifie que la moqué de l'objet est une sous-classe de la LinkedList. Espérons que cela aide.
Même si le simulacre de l'objet est une sous-classe de la Linkedlist, afin de créer de la présente sous-classe de l'objet, vous devez créer parent de la classe de l'objet. (sur des parent les constructeurs devraient avoir été appelé)
Même si l'exception est générée à partir du code réel, l'instance est toujours un Mockito s'en moquer, et Mockito est à l'aide de tours (via Objenesis) pour contourner le constructeur par défaut de tout se moquaient de l'objet (dans l'ordre pour être en mesure de se moquer de types avec un constructeur privé). Aussi, une maquette sera jamais initialise les champs, car il ne devrait pas avoir à le faire. Ce que vous voulez atteindre est une fantaisie partielle, vous pouvez le faire via un
spy
. Notez également que partielle se moque indique généralement il y a un défaut de conception dans le code à tester.Vous pouvez également utiliser la délégation depuis 1.9.5, qui est différent d'un espion : ou via
AdditionalAnswers.delegatesTo()
OriginalL'auteur Ajay George
Vous demande seulement d'Mockito à l'appel de la vraie chose sur clair, l'objet sous-jacent est encore un faux créé par Mockito pour vous. Si vous avez besoin d'un réel LinkedList alors utilisez simplement la LinkedList - seulement le plus chauffée puriste de la BDD voudrais vous dire, à se moquer de tout ce qui vous entoure. Je veux dire, vous n'êtes pas en se moquant de Chaînes êtes-vous?
Mockito auteur lui-même a dit que l'appel à la vraie chose doit être utilisé à peine, habituellement seulement pour le test d'un code de legs.
Si vous avez besoin d'espionner l'objet réel (les invocations) puis Mockito a une fonction pour cela aussi:
Avec spy, vous pouvez toujours le talon d'une méthode si vous avez besoin. Il fonctionne essentiellement comme un simulacre, mais n'est-ce pas 😉
Comme je l'ai triste: on vous demande seulement d'Mockito à l'appel de la vraie chose sur clair, l'objet lui-même n'est pas instancié, mockito crée un faux pour vous-dessous. J'ai révisé la réponse pour le rendre plus clair. Je vais essayer d'être plus explicite la prochaine fois.
N'en déplaise 🙂 je voulais Simplement faire remarquer que, parfois, il y a des réponses de ne pas répondre à la question, mais le questionnement de l'OP du cours de l'action. Et ce sont parfois downvoted pour le faire. J'ai trouvé une bonne pratique dans la réponse à la première raconter l'OP pourquoi il ne fonctionne pas ce qu'il fait (et donc de répondre à la question) et puis ce qui suggère une alternative, si j'en ai une à vous offrir. Après votre modification, +1 pour vous, trop.
C'est une très juste remarque, j'ai juste supposé que "vous demande seulement d'Mockito à l'appel de la vraie chose sur clear" implique que rien d'autre n'est réel avec cet objet. Néanmoins, un très bon point, ce n'était pas clair du tout 🙂
vous avez mentionné que le code appelle la vraie chose sur la méthode claire. comment se fait la méthode est réel, mais l'objet est faux?
OriginalL'auteur theadam
Quand vous vous moquez d'une classe de l'objet que vous utilisez est un faux, par conséquent, les variables ne sont pas instanciés et les méthodes ne fonctionnent pas comme prévu. Vous pouvez utiliser la réflexion pour définir une valeur pour l'en-tête mais je ne le recommande pas. Comme theadam dit, la meilleure chose à faire serait d'utiliser une liste.
OriginalL'auteur Vlad Topala