Ich bin ein Neuling in der Entwicklung und insbesondere bei Unit-Tests. Ich denke, meine Anforderung ist ziemlich einfach, aber ich bin gespannt darauf, andere Gedanken dazu zu kennen.
Angenommen, ich habe zwei Klassen wie diese -
public class First {
Second second ;
public First(){
second = new Second();
}
public String doSecond(){
return second.doSecond();
}
}
class Second {
public String doSecond(){
return "Do Something";
}
}
Angenommen, ich schreibe Unit-Test-to-Test- First.doSecond()
Methode. Angenommen, ich möchte die Second.doSecond()
Klasse so verspotten . Ich benutze Mockito, um dies zu tun.
public void testFirst(){
Second sec = mock(Second.class);
when(sec.doSecond()).thenReturn("Stubbed Second");
First first = new First();
assertEquals("Stubbed Second", first.doSecond());
}
Ich sehe, dass die Verspottung nicht wirksam wird und die Behauptung fehlschlägt. Gibt es keine Möglichkeit, die Mitgliedsvariablen einer Klasse zu verspotten, die ich testen möchte? ?
Dies ist nicht möglich, wenn Sie Ihren Code nicht ändern können. Aber ich mag Abhängigkeitsinjektion und Mockito unterstützt sie:
Dein Test:
Das ist sehr schön und einfach.
quelle
Wenn Sie sich Ihren Code genau ansehen, werden Sie feststellen, dass die
second
Eigenschaft in Ihrem Test immer noch eine Instanz vonSecond
und kein Mock ist (Sie geben den Mockfirst
in Ihrem Code nicht weiter).Der einfachste Weg wäre, einen Setter für
second
in derFirst
Klasse zu erstellen und ihm den Mock explizit zu übergeben.So was:
Eine andere Möglichkeit wäre, eine
Second
Instanz alsFirst
Konstruktorparameter zu übergeben.Wenn Sie den Code nicht ändern können, besteht meiner Meinung nach die einzige Möglichkeit darin, Reflection zu verwenden:
Aber Sie können es wahrscheinlich, da es selten ist, Tests mit Code durchzuführen, den Sie nicht kontrollieren (obwohl man sich ein Szenario vorstellen kann, in dem Sie eine externe Bibliothek testen müssen, weil der Autor dies nicht getan hat :)).
quelle
@Mock
und Annotieren Sie First mit@InjectMocks
und instanziieren Sie First im Initialisierer. Mockito wird automatisch das Beste tun, um einen Ort zu finden, an dem das zweite Modell in die erste Instanz eingefügt werden kann, einschließlich des Festlegens privater Felder, die dem Typ entsprechen.@Mock
war um in 1.5 (vielleicht früher, ich bin nicht sicher). 1.8.3 eingeführt@InjectMocks
sowie@Spy
und@Captor
.Wenn Sie die Mitgliedsvariable nicht ändern können, können Sie PowerMockit verwenden und aufrufen
Das Problem ist nun, dass JEDER Aufruf von new Second dieselbe verspottete Instanz zurückgibt. Aber in Ihrem einfachen Fall wird dies funktionieren.
quelle
Ich hatte das gleiche Problem, bei dem kein privater Wert festgelegt wurde, weil Mockito keine Superkonstruktoren aufruft. Hier ist, wie ich das Verspotten mit Nachdenken verstärke.
Zuerst habe ich eine TestUtils-Klasse erstellt, die viele hilfreiche Dienstprogramme enthält, einschließlich dieser Reflexionsmethoden. Der Reflexionszugriff ist jedes Mal etwas schwierig zu implementieren. Ich habe diese Methoden erstellt, um Code für Projekte zu testen, die aus dem einen oder anderen Grund kein Verspottungspaket hatten, und ich wurde nicht eingeladen, ihn einzuschließen.
Dann kann ich die Klasse mit einer privaten Variablen wie dieser testen. Dies ist nützlich, um sich tief in Klassenbäumen zu verspotten, auf die Sie ebenfalls keine Kontrolle haben.
Ich habe meinen Code aus meinem eigentlichen Projekt hier auf Seite geändert. Möglicherweise liegt ein oder zwei Kompilierungsprobleme vor. Ich denke, Sie haben eine allgemeine Vorstellung. Nehmen Sie den Code und verwenden Sie ihn, wenn Sie ihn nützlich finden.
quelle
Viele andere haben Ihnen bereits geraten, Ihren Code zu überdenken, um ihn testbarer zu machen - gute Ratschläge und normalerweise einfacher als das, was ich vorschlagen werde.
Wenn Sie den Code nicht ändern können, um ihn testbarer zu machen, wählen Sie PowerMock: https://code.google.com/p/powermock/
PowerMock erweitert Mockito (damit Sie kein neues Mock-Framework erlernen müssen) und bietet zusätzliche Funktionen. Dies beinhaltet die Möglichkeit, dass ein Konstruktor einen Mock zurückgibt. Kraftvoll, aber etwas kompliziert - verwenden Sie es also mit Bedacht.
Sie verwenden einen anderen Mock-Läufer. Und Sie müssen die Klasse vorbereiten, die den Konstruktor aufruft. (Beachten Sie, dass dies ein häufiges Problem ist. Bereiten Sie die Klasse vor, die den Konstruktor aufruft, nicht die konstruierte Klasse.)
Anschließend können Sie in Ihrem Testaufbau die whenNew-Methode verwenden, damit der Konstruktor einen Mock zurückgibt
quelle
Ja, dies kann durchgeführt werden, wie der folgende Test zeigt (geschrieben mit der von mir entwickelten JMockit-Mocking-API):
Mit Mockito kann ein solcher Test jedoch nicht geschrieben werden. Dies liegt an der Art und Weise, wie das Verspotten in Mockito implementiert wird, wo eine Unterklasse der zu verspottenden Klasse erstellt wird. Nur Instanzen dieser "Schein" -Unterklasse können ein verspottetes Verhalten aufweisen. Daher muss der getestete Code sie anstelle einer anderen Instanz verwenden.
quelle
Wenn Sie eine Alternative zu ReflectionTestUtils von Spring in mockito wünschen, verwenden Sie
quelle