[JAVA] Hinweise für diejenigen, die mit JMockit leben

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.

Was ist JMockit?

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).

Funktionen des JMockit-Versions-Upgrades

Alle paar Monate wird eine Nebenversion veröffentlicht. Sie können frühere Versionen auf dieser Seite überprüfen:

JMockit - Development history

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.

Mockito wird gegenüber JMockit empfohlen!

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.

Workflow für Versionsaktualisierungen

Sie können durch die folgenden Vorgänge ein Upgrade durchführen.

  1. Erhöhen Sie die Version von JMockit
  2. Schreiben Sie Funktionen neu, die beim Versions-Upgrade abgeschafft wurden
  3. Kompilieren
  4. Ändern Sie den Code, bis er kompiliert wird
  5. Testausführung
  6. Ändern Sie den Code, bis der Test bestanden ist

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

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.

JMockit - Tutorial

Veraltete Hauptfunktionen und Umschreibemethoden

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.).

So führen Sie den Test aus

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) Anmerkung

Wie oben erwähnt, ist es veraltet. Löschen Sie es einfach.

1 Argument 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.

1. Ändern Sie das Feld in "package-private" oder "public"

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;

2. Verwenden Sie "@ Tested" und "@ Injectable"

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.

Methoden wie "System" werden verspottet

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.

Schreibstile, die in der neuesten Version vermieden werden sollten

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 **.

Schreiben Sie einen weiteren Methodenaufruf in das Argument / den Rückgabewert

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;
}};

Schreiben Sie eine irrelevante Methode in "Erwartungen" mit Argumenten

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

Hinweise für diejenigen, die mit JMockit leben
[Für diejenigen, die Portfolios erstellen] Mit Ransack erstellte Suchfunktion
[Für diejenigen, die Portfolios erstellen] Verwendung von binding.pry mit Docker
Überprüfen Sie die Notizen für die Klasse java.util.Scanner
Java Programmer Gold SE 8 Qualifikationsübersicht (für diejenigen, die mit Java vertraut sind)
Überprüfen Sie die Notizen für die Klasse java.util.Optional
Ein Überprüfungshinweis für die Klasse java.util.Objects
Überprüfen Sie die Notizen für das Paket java.time.temporal
Zugriff mit Selen als Gegenmaßnahme für navigator.webdriver
Ein Hinweis, als jemand, der bis gestern Java Java war, Scala berührte
Erstellen Sie eine Vorlage für das iOS14-Widget mit Absichtskonfiguration.
[Java-Grundlagen] Lassen Sie uns ein Dreieck mit einer for-Anweisung erstellen
Ein Hinweis zum Initialisieren von Feldern im Java-Lernprogramm
[Hinweis] Erstellen Sie eine Python3-Umgebung mit Docker in EC2
[Für diejenigen, die Portfolios erstellen] Verwendung von Font-Awesome-Rails
[Hinweis] Erstellen Sie mit Docker eine Java-Umgebung von Grund auf neu
(Für mich) Baue ein Git-Labor mit Ubuntu 18.04 + Docker für zu Hause (Hinweis)
Ein Janken-Spiel für zwei Spieler mit Java, das zwischen Threads konkurriert
Für Personen, die ein Dokument im Firestore gelöscht haben, aber die Untersammlung nicht verschwindet