Manière correcte de l'unité de la classe de test à l'intérieur de la classe
Une classe interne est de classe B. la Classe A a une liste privée de la classe B les objets qu'il met à la disposition par le biais de getBs, addB, et removeB méthodes. Comment puis-je l'unité de test de la removeB méthode?
J'espérais créer deux se moque de la classe B, de l'ajout de chaque, puis supprimez l'un d'eux à deux reprises (pour conséquence de supprimer à la fois). Cependant, depuis j'ai appris par le biais de l'échec que la méthode equals ne sera pas appelé sur les objets fantaisie.
Était-il idiot (ou impossible) de tenter d'isoler l'extérieur de la classe de son intérieur de la classe de test unitaire?
Exemple de code suit
Classe de test:
import java.util.ArrayList;
import java.util.List;
public class Example {
private List<Inner> inners = new ArrayList<Inner>();
public List<Inner> getInners() {
return inners;
}
public void addInner(Inner i) {
inners.add(i);
}
public void removeInner(Inner i) {
inners.remove(i);
}
/**
* equalityField represents all fields that are used for testing equality
*/
public class Inner {
private int equalityField;
private int otherFields;
public int getEqualityField() {
return equalityField;
}
public Inner(int field) {
this.equalityField = field;
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (o.getClass() != this.getClass())
return false;
Inner other = (Inner) o;
if (equalityField == other.getEqualityField())
return true;
return false;
}
}
}
Cas de Test qui ne fonctionne pas si grande:
import static org.junit.Assert.*;
import org.junit.Test;
import org.easymock.classextension.EasyMock;
public class ExampleTest {
@Test
public void testRemoveInner() {
Example.Inner[] mockInner = new Example.Inner[2];
mockInner[0] = EasyMock.createMock(Example.Inner.class);
mockInner[1] = EasyMock.createMock(Example.Inner.class);
Example e = new Example();
e.addInner(mockInner[0]);
e.addInner(mockInner[1]);
e.removeInner(mockInner[0]);
e.removeInner(mockInner[0]);
assertEquals(0, e.getInners().size());
}
}
OriginalL'auteur Matt | 2011-11-24
Vous devez vous connecter pour publier un commentaire.
Pourquoi avez-vous à moquent de vous à l'intérieur de la classe? Si j'ai été confronté à ce problème, je voudrais juste utiliser la classe comme est et de tester le comportement de l'extérieur de la classe fonctionne comme prévu. Vous n'avez pas besoin de se moquer de l'intérieur de la classe pour le faire.
En aparté: en surchargeant la méthode equals() il est également conseillé de remplacer le hashCode() la méthode, trop.
Plusieurs années trop tard, mais j'ai pensé que je devrais fournir quelques raisons pour lesquelles quelqu'un voudrait le simulacre: L'intérieur de la classe qu'il est responsable de certains d'e / s réseau qui ne devrait pas arriver dans un environnement de test.
Je ne pense pas que cette réponse est logique. Il y aura une certaine interaction entre l'intérieur et l'extérieur de la classe, et il est évident que cela pourrait avoir besoin d'être testé. Pourquoi est-ce accepté de répondre?
OriginalL'auteur Mark
Tout d'abord, la réponse à votre question: Oui, c'est généralement une mauvaise idée de les essayer et de les séparer un à l'intérieur et à l'extérieur de la classe lors de tests unitaires. Généralement, c'est parce que les deux sont intimement liés, par exemple Intérieure n'a de sens que dans le contexte de l'Extérieur, l'Extérieur dispose d'une usine méthode qui renvoie une implémentation d'une interface, d'un Interne. Si les deux ne sont pas vraiment liés, puis les séparer en deux fichiers. Il rend votre test la vie plus facile.
Deuxièmement, (à l'aide du code ci-dessus à titre d'exemple), vous n'avez pas besoin de simuler le code ci-dessus. Il suffit de créer certains cas, et vous allez loin. Il semble que vous avez assez de travailler avec. Vous pouvez toujours faire quelque chose comme:
Ne se moque nécessaire.
Troisièmement, essayer de travailler sur ce que vous êtes réellement tester. Dans le code ci-dessus, vous effectuez le test que si je ajouter quelque chose à une liste, alors je peux le supprimer. Par la manière, vous dites que si il y a plusieurs objets qui sont "égales"; le code ci-dessus ne fait pas que, à partir de la définition de Collection#remove():
Est-ce vraiment ce que vous voulez tester?
Quatrièmement, si vous mettez en œuvre d'égal à égal, de mettre en œuvre hashCode (voir Primordial equals et hashCode en Java).
OriginalL'auteur Matthew Farwell
Comme un TDD newb qui a juste rencontré cette situation pour la première fois, j'ai trouvé que je suis arrivé à avoir "invérifiables" inner classes comme un résultat de refactoring, et si à l'aide d'un "pur" TDD approche, je me demande si vous pourriez vous retrouver à l'intérieur des classes de toute autre manière.
Le problème, c'est que, à supposer que l'une ou plusieurs références sont faites à l'extérieur de la classe de l'objet à partir de l'intérieur de la classe, ce refactoring cassera souvent un ou plusieurs tests. La raison est assez simple: votre maquette de l'objet, si un
spy
, est en fait un wrapper autour d'un objet réel... mais à l'intérieur des classes sera toujours la référence de l'objet réel, de sorte qu'il sera souvent le cas que d'essayer d'appliquer se moque de
myClass
ne fonctionne pas. Pire, même sans se moque il existe une forte probabilité que la chose échoue complètement et inexplicablement aller juste au sujet de son activité normale. Sachez également que votre espion n'aura pas d'exécuter la réelle méthode de constructeur pour lui-même: beaucoup de choses à aller mal.Étant donné que le développement de nos de nos tests est un investissement dans la qualité, il me semble que ce serait une terrible honte juste pour dire: "OK, je vais laisser tomber ce test".
Je suggérer qu'il y a deux options:
si vous remplacez votre intérieur de la classe direct accès à l'extérieur des champs de classe avec getter/setter (qui peut être
private
, assez bizarrement), cela signifie que c'est le se moquer de's méthodes qui seront utilisées... et donc la simulation de champs. Les tests existants devrait ensuite continuer à passer.l'autre possibilité est de refactoriser que l'intérieur de la classe pour en faire un libre-debout classe, une instance qui remplace l'intérieur de votre classe, et le transfert d'une ou de plusieurs méthodes de test d'une nouvelle classe de test pour cette nouvelle classe. Vous serez alors face à la (simple) de gréement choses afin que les références à l'extérieur de la classe d'objet sont paramétrées (c'est à dire 99% des cas, passée en paramètre du constructeur) et peuvent ensuite se moque de lui convenablement. Cela ne devrait pas être trop difficile. Bien que vous devrez peut-être ajouter adapté getter/setter pour
private
champs à l'extérieur de la classe et/ou de faire un ou plusieurs de sesprivate
méthodespackage-private
. À partir de ce point à l'intérieur de la classe devient une "boîte noire" aussi loin que les tests de l'extérieur de la classe.En utilisant soit l'approche que vous avez subi aucune perte de qualité.
OriginalL'auteur mike rodent
Vous pouvez étendre la classe sous test (A) avec un but en ATest classe qui offre une méthode publique qui vous permettra d'œil sur la liste privée de B
OriginalL'auteur Miquel