Neulich habe ich daran gearbeitet, die im Unit-Test verwendete Version von JMockit zu aktualisieren (1.13 → 1.46). Notieren Sie sich die Änderungen im alten und neuen JMockit und wie Sie diese beim Upgrade beheben können.
Wir hoffen, dass es für die folgenden zwei Arten von Menschen nützlich sein wird.
JMockit ist eine Scheinbibliothek für Java. Sie können das Verhalten vorhandener Methoden im Unit-Test ersetzen (verspotten).
Offizielle JMockit-Seite → Das JMockit-Test-Toolkit
Ersetzungen werden mit dem Instanzinitialisierer und den speziellen Instanzvariablen "result" und "times" definiert.
new Expectations() {{
obj.method(arg1, arg2, arg3);
result = value;
times = 2;
}};
Es unterstützt auch ziemlich leistungsfähige Operationen und kann wie folgt ersetzt werden (Details finden Sie auf der offiziellen Seite).
Alle paar Monate wird eine Nebenversion veröffentlicht. Sie können frühere Versionen auf dieser Seite überprüfen:
Wie Sie dem Verlauf entnehmen können, ist JMockit eine Richtlinie, die ** alte Funktionen immer mehr abschneidet **. Zum Beispiel ist die Methode "Deencapsulation.setField" in 2 Monaten und 2 Versionen veraltet.
Version 1.45 (Jan 27, 2019): Removed the Deencapsulation.setField methods, which were deprecated in version 1.44.
Version 1.44 (Nov 25, 2018): Deprecated the Deencapsulation.setField methods, in favor of @Tested and @Injectable.
Daher **, wenn Sie versuchen, die Version sofort zu aktualisieren, sind viele Änderungen erforderlich und die Arbeit wird schwierig **.
Wir empfehlen entweder.
Zu den Rivalen von JMockit gehört Mockito. Mockito hat mehr Benutzer und eine natürlichere Notation (besonders wenn Sie an Rubys RSpec gewöhnt sind).
Auch Mockito allein kann nur normale Methoden ersetzen, aber in Kombination mit Powermock können dieselben leistungsstarken "schmutzigen" Änderungen wie bei JMockit vorgenommen werden. Ich werde.
//Bild der Mockito-Notation
when(obj.method(arg1, arg2, arg3)).thenReturn(value);
Daher wird empfohlen, wenn möglich von ** J Mockit nach Mockito ** zu wechseln.
In diesem Produkt habe ich die Migration nach Mockito aufgegeben, da viele Tests mit JMockit durchgeführt wurden.
Sie können durch die folgenden Vorgänge ein Upgrade durchführen.
Wie unter "Schreiben zur Vermeidung in der neuesten Version" erläutert, gibt es Fälle, in denen die Kompilierung erfolgreich ist, aber nicht wie beabsichtigt funktioniert. Wenn der Test fehlschlägt, vermuten Sie es.
Darüber hinaus wird nicht empfohlen, ein Upgrade von der alten Version auf die neueste Version durchzuführen, da zu viele Änderungen vorgenommen werden und ein Ausfall auftritt.
Ebenfalls,
Ich glaube nicht, dass es so eine Abkürzung gibt. ** Wir empfehlen, dass Sie jeweils eine Version aktualisieren **.
Lesen Sie die ** neueste Version des Tutorials **, bevor Sie ein Upgrade durchführen oder Tests schreiben.
JMockit ist in erster Linie eine Bibliothek mit einer starken Gewohnheit. Es tut weh, wenn ich denke: "Es ist das gleiche wie bei Mockito, nur der Schreibstil ist anders." Wenn Sie beispielsweise ein Scheinobjekt für eine Klasse erhalten, die * @ Mocked
ist, werden alle Instanzen dieser Klasse verspottet *.
Wie oben erwähnt, wurden die Funktionen mutig überarbeitet und abgeschafft, und der Schreibstil hat sich erheblich geändert. Erfahrene JMockit sollten den Code auch lesen, bevor sie ihn berühren.
Haben Sie die neueste Version des Tutorials gelesen?
OK!
Hier sind einige der Änderungen in früheren Versionen, die wahrscheinlich große Auswirkungen haben werden (es tut mir leid für die kleinen Funktionen, aber lesen Sie die Versionshinweise usw.).
Zuvor wurde JMockit geladen, als die JUnit-Testklasse mit "@ RunWith (JMockit.class)" versehen wurde.
Jetzt hat sich die Methode geändert. Wenn Sie beim Ausführen eines Komponententests die JMockit-JAR-Datei als Java-Agent als VM-Option angeben (siehe Abbildung unten), wird JMockit geladen.
-javaagent:/path/to/jmockit-1.46.jar
Stellen Sie für IntelliJ die folgende Position ein.
"Modulname neben der Schaltfläche Ausführen in der Symbolleiste" → Konfigurationen bearbeiten → Vorlagen → JUnit → Konfigurationen → VM-Optionen
@ RunWith (JMockit.class)
AnmerkungWie oben erwähnt, ist es veraltet. Löschen Sie es einfach.
return
Verwenden Sie für das Ein-Argument "return" stattdessen "result =". Sie können weiterhin "return" mit zwei oder mehr Argumenten verwenden.
Es ist schwierig, "Retouren" einzeln umzuschreiben, aber ich habe darüber in einem anderen Artikel geschrieben. Lesen Sie daher bitte darauf (→ Wie habe ich Retouren (Objekt) in JMockit sicher ersetzt? " ).
// Old
new Expectations() {{
obj.method(arg1, arg2, arg3); returns(value);
}};
// New
new Expectations() {{
obj.method(arg1, arg2, arg3); result = value;
}};
NonStrictExpectations
"NonStrictExpectations" war die "Version von" Expectations ", die auch dann keinen Fehler verursacht, wenn die ersetzte Methode nicht aufgerufen wird".
Ersetzen Sie es wie unten gezeigt durch "Erwartungen" und setzen Sie die Mindestanzahl von Anrufen mit "minTimes = 0" auf 0.
new Expectations() {{
mock.get(0); result = "1"; minTimes = 0;
}};
Außerdem lautet "Ich habe die Methode ersetzt, aber sie wird nicht aufgerufen"
In vielen Fällen überprüfen Sie bitte den Testfall.
StrictExpectations
Schreiben Sie es einfach als Erwartungen um.
Deencapsulation
Die Entkapselung war die Möglichkeit, private Felder zu durchsuchen und zu ändern.
Lockern Sie die Zugriffsbeschränkungen für die Felder, die mit "Entkapselung" geändert wurden, und ermöglichen Sie den Zugriff auf sie mit "." Aus dem Test. Kommentieren Sie das Feld mit Guavas "@ VisibleForTesting".
Sie werden Änderungen am Code auf der Hauptseite vornehmen, aber das Ändern des Zugriffsmodifikators sollte normalerweise nicht zu einem Fehler führen [^ 1].
[^ 1]: Natürlich wäre es ein Problem, wenn auf das Feld, das zum Testen veröffentlicht wird (ich möchte es privat machen), über den Produktionscode zugegriffen wird. Wenn Sie jedoch "@ VisibleForTesting" verwenden, können Sie unterscheiden, ob es sich um ein Feld handelt, auf das Sie zugreifen können. Du solltest dazu fähig sein.
// Old
//Körpercode
class Spam {
// ...
private Foo field;
// ...
}
//Testcode
x = Deencapsulation.getField(obj, "field");
// New
// Old
//Körpercode
class Spam {
// ...
@VisibleForTesting
Foo field;
// ...
}
//Testcode
x = obj.field;
JMockit verfügt über einen DI-Mechanismus zum Testen.
Wenn Sie Deencapsulation.setField
verwenden, um das zu testende Objekt zu verspotten, wird es durch DI ersetzt.
4 Instantiation and injection of tested classes
.newMockInstance()
Stellen Sie sicher, dass Sie die Scheininstanz mit @Mocked erhalten. Ein einfaches Umschreiben ist nicht möglich.
In älteren Versionen wurde JMockit durch eine beliebige Methode ersetzt. Native Methoden wie "System.currentTimeMillis" werden in der aktuellen Version nicht ersetzt.
Entwerfen Sie Ihre Tests neu, um den Austausch selbst zu vermeiden, oder ersetzen Sie nicht native Methoden.
Der Teil des aktualisierten Produkts, der "System.currentTimeMillis" verwendet, wurde geändert, um stattdessen "neues Datum" zu ersetzen.
Obwohl in der Dokumentation nicht ausdrücklich angegeben, gibt es ein Muster, das ** in der alten Version einwandfrei funktioniert und kompiliert, in der neuen Version jedoch nicht funktioniert **.
Wenn Sie einen anderen Methodenaufruf als Methodenargument oder Rückgabewert in "Expectations" schreiben, wird dieser möglicherweise nicht richtig ersetzt. Argumente und Rückgabewerte sollten temporären Variablen außerhalb von "Erwartungen" zugewiesen werden. Es ist besser, sie vom Standpunkt der Lesbarkeit zu trennen.
// NG
new Expectations() {{
foo.method(getX(), getY()); result = getHogeList();
}};
// OK
X x = getX();
Y y = getY();
HogeList hogeList = getHogeList();
new Expectations() {{
foo.method(x, y); result = hogeList;
}};
Wenn Sie nur eine bestimmte Methode einer Klasse ersetzen möchten oder wenn Sie nur eine bestimmte Instanz einer Methode ersetzen möchten, geben Sie die Klasse oder Instanz unter "Erwartungen" an.
Wenn Sie zu diesem Zeitpunkt das Argument "Erwartungen" mit dem irrelevanten Methodenaufruf mischen, können Sie möglicherweise nicht richtig verspotten. Separate irrelevante Methodenaufrufe in separate "Erwartungen". Es ist besser, sie vom Standpunkt der Lesbarkeit zu trennen.
// NG
new Expectations(foo) {{
foo.method(x, y); result = v;
other.othersMethod(); result = value; //Diese Methode ändert sich nicht
}};
// OK
new Expectations(foo) {{
foo.method(x, y); result = v;
}};
new Expectations() {{ //Erwartungen teilen
other.othersMethod(); result = value;
}};
Recommended Posts