Ich habe eine Abschlussklasse, so etwas wie:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
Ich benutze diese Klasse in einer anderen Klasse wie dieser:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
und in meiner JUnit-Testklasse Seasons.java
möchte ich die RainOnTrees
Klasse verspotten . Wie kann ich das mit Mockito machen?
Antworten:
Das Verspotten von endgültigen / statischen Klassen / Methoden ist nur mit Mockito v2 möglich.
füge dies in deine Gradle-Datei ein:
Dies ist mit Mockito v1 in den Mockito-FAQ nicht möglich :
quelle
Mockito 2 unterstützt jetzt endgültige Klassen und Methoden!
Aber im Moment ist das eine "Inkubations" -Funktion. Zum Aktivieren sind einige Schritte erforderlich, die unter Was ist neu in Mockito 2 beschrieben :
quelle
org.mockito.plugins.MockMaker
Datei im richtigen Ordner ablegen.Sie können eine Abschlussklasse mit Mockito nicht verspotten, da Sie dies nicht alleine tun können.
Ich erstelle eine nicht endgültige Klasse, um die letzte Klasse zu verpacken und als Delegat zu verwenden. Ein Beispiel dafür ist
TwitterFactory
Klasse, und dies ist meine verspottbare Klasse:Der Nachteil ist, dass es viel Boilerplate-Code gibt; Der Vorteil besteht darin, dass Sie einige Methoden hinzufügen können, die sich auf Ihr Anwendungsgeschäft beziehen können (z. B. die getInstance, die im obigen Fall einen Benutzer anstelle eines accessToken verwendet).
In Ihrem Fall würde ich eine nicht endgültige
RainOnTrees
Klasse erstellen , die an die letzte Klasse delegiert. Oder wenn Sie es nicht endgültig machen können, wäre es besser.quelle
@Delegate
, um einen Großteil der Boilerplate zu handhaben.füge dies in deine Gradle-Datei ein:
Dies ist eine Konfiguration, mit der Mockito mit Abschlussklassen funktioniert
quelle
org.mockito.exceptions.base.MockitoInitializationException: Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Verwenden Sie Powermock. Dieser Link zeigt, wie es geht: https://github.com/jayway/powermock/wiki/MockFinal
quelle
Powermock
verspottende Abschlussklassen und statische Methoden lustig gemacht, um meine Abdeckung zu erhöhen, die offiziell überprüft wurdeSonarqube
. Die Abdeckung betrug seit SonarQube 0%. Aus irgendeinem Grund werden Klassen, die Powermock verwenden, nicht erkannt. Ich habe mir und meinem Team einige Zeit genommen, um dies anhand eines Online-Threads zu realisieren. Das ist nur einer der Gründe, vorsichtig mit Powermock umzugehen und es wahrscheinlich nicht zu verwenden.Nur um nachzufolgen. Bitte fügen Sie diese Zeile Ihrer Gradle-Datei hinzu:
Ich habe verschiedene Versionen von Mockito-Core und Mockito-All ausprobiert. Keiner von ihnen arbeitet.
quelle
Ich denke, Sie haben es geschafft,
final
weil Sie verhindern möchten, dass andere Klassen erweitert werdenRainOnTrees
. Wie Effective Java vorschlägt (Punkt 15), gibt es eine andere Möglichkeit, eine Klasse für die Erweiterung nahe zu halten, ohne sie zu erstellenfinal
:Entfernen Sie das
final
Schlüsselwort.Machen Sie seinen Konstruktor
private
. Keine Klasse kann es erweitern, da sie densuper
Konstruktor nicht aufrufen kann .Erstellen Sie eine statische Factory-Methode, um Ihre Klasse zu instanziieren.
Mit dieser Strategie können Sie Mockito verwenden und Ihre Klasse zur Erweiterung mit wenig Boilerplate-Code geschlossen halten.
quelle
Ich hatte das gleiche Problem. Da die Klasse, die ich verspotten wollte, eine einfache Klasse war, habe ich einfach eine Instanz davon erstellt und diese zurückgegeben.
quelle
Probieren Sie es aus:
Es hat bei mir funktioniert. "SomeMockableType.class" ist die übergeordnete Klasse dessen, was Sie verspotten oder ausspionieren möchten, und someInstanceThatIsNotMockableOrSpyable ist die tatsächliche Klasse, die Sie verspotten oder ausspionieren möchten.
Weitere Details finden Sie hier
quelle
Eine andere Problemumgehung, die in einigen Fällen zutreffen kann, besteht darin, eine Schnittstelle zu erstellen, die von dieser letzten Klasse implementiert wird, den Code so zu ändern, dass die Schnittstelle anstelle der konkreten Klasse verwendet wird, und dann die Schnittstelle zu verspotten. Auf diese Weise können Sie den Vertrag (Schnittstelle) von der Implementierung (letzte Klasse) trennen. Wenn Sie wirklich an die letzte Klasse binden möchten, gilt dies natürlich nicht.
quelle
Eigentlich gibt es einen Weg, den ich zum Spionieren benutze. Es würde für Sie nur funktionieren, wenn zwei Voraussetzungen erfüllt sind:
Bitte erinnern Sie sich an Punkt 16 von Effective Java . Sie können einen Wrapper (nicht final) erstellen und alle Aufrufe an die Instanz der final class weiterleiten:
Jetzt können Sie Ihre letzte Klasse nicht nur verspotten, sondern auch ausspionieren:
quelle
In Mockito 3 und mehr habe ich das gleiche Problem und habe es wie über diesen Link behoben
Mock Final Classes und Methoden mit Mockito wie folgt
quelle
Zeitersparnis für Personen, die mit demselben Problem (Mockito + Final Class) auf Android + Kotlin konfrontiert sind. Wie in Kotlin sind Klassen standardmäßig endgültig. Ich habe eine Lösung in einem der Google Android-Beispiele mit Architekturkomponente gefunden. Hier ausgewählte Lösung: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Erstellen Sie folgende Anmerkungen:
Ändern Sie Ihre Gradle-Datei. Nehmen Sie ein Beispiel von hier: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
Jetzt können Sie jede Klasse mit Anmerkungen versehen, um sie zum Testen zu öffnen:
quelle
Dies ist möglich, wenn Sie Mockito2 mit der neuen Inkubationsfunktion verwenden, die das Verspotten der endgültigen Klassen und Methoden unterstützt.
Wichtige Punkte:
1. Erstellen Sie eine einfache Datei mit dem Namen "org.mockito.plugins.MockMaker" und legen Sie sie in einem Ordner mit dem Namen "mockito-extensions" ab. Dieser Ordner sollte im Klassenpfad verfügbar gemacht werden.
2. Der Inhalt der oben erstellten Datei sollte eine einzelne Zeile sein, wie unten angegeben:
mock-maker-inline
Die beiden oben genannten Schritte sind erforderlich, um den Mockito-Erweiterungsmechanismus zu aktivieren und diese Anmeldefunktion zu verwenden.
Beispielklassen sind wie folgt: -
FinalClass.java
}}
Foo.java
}}
FooTest.java
}}
Ich hoffe es hilft.
Kompletter Artikel hier verspottet-das-Unversöhnliche .
quelle
Ja, das gleiche Problem hier, wir können eine Abschlussklasse mit Mockito nicht verspotten. Um genau zu sein, kann Mockito Folgendes nicht verspotten / ausspionieren:
Die Verwendung einer Wrapper-Klasse scheint mir jedoch ein hoher Preis zu sein. Holen Sie sich stattdessen PowerMockito.
quelle
Ich denke, Sie müssen im Prinzip mehr nachdenken. Stattdessen verwenden Sie als letzte Klasse seine Schnittstelle und die Scheinschnittstelle.
Dafür:
hinzufügen
und verspotten Sie Schnittstelle:
quelle
Bitte schauen Sie sich JMockit an . Es verfügt über eine umfangreiche Dokumentation mit vielen Beispielen. Hier haben Sie eine Beispiellösung für Ihr Problem (zur Vereinfachung habe ich einen Konstruktor hinzugefügt
Seasons
, um eine verspotteteRainOnTrees
Instanz einzufügen ):quelle
Lösungen von RC und Luigi R. Viggiano zusammen sind möglicherweise die beste Idee.
Obwohl Mockito nicht beabsichtigt ist , Abschlussklassen zu verspotten, ist der Delegierungsansatz möglich . Das hat seine Vorteile:
In Ihrem Testfall leiten Sie die Anrufe absichtlich an das zu testende System weiter. Daher ist Ihre Dekoration von Natur aus nicht geeignet alles tun.
Daher kann Ihr Test auch zeigen, dass der Benutzer die API nur dekorieren kann, anstatt sie zu erweitern.
Subjektiver: Ich ziehe es vor, die Frameworks auf ein Minimum zu beschränken, weshalb JUnit und Mockito normalerweise für mich ausreichen. In der Tat zwingt mich die Einschränkung dieses Weges manchmal auch dazu, mich endgültig umzugestalten.
quelle
Wenn Sie versuchen , Unit-Test unter dem laufen Testordner ist die Top-Lösung in Ordnung. Folgen Sie einfach dem Hinzufügen einer Erweiterung.
Aber wenn Sie es mit Android-bezogenen Klassen wie Kontext oder Aktivität ausführen möchten, die sich im Android- Test- Ordner befinden, ist die Antwort für Sie.
quelle
Fügen Sie diese Abhängigkeiten hinzu, um mockito erfolgreich auszuführen:
testImplementation 'org.mockito: mockito-core: 2.24.5'
testImplementation "org.mockito: mockito-inline: 2.24.5"
quelle
Wie andere bereits gesagt haben, funktioniert dies mit Mockito nicht sofort. Ich würde vorschlagen, Reflection zu verwenden, um die spezifischen Felder für das Objekt festzulegen, das vom zu testenden Code verwendet wird. Wenn Sie dies häufig tun, können Sie diese Funktionalität in eine Bibliothek einbinden.
Abgesehen davon, wenn Sie derjenige sind, der die Klassen als endgültig markiert, hören Sie damit auf. Ich bin auf diese Frage gestoßen, weil ich mit einer API arbeite, bei der alles als endgültig markiert wurde, um meine berechtigte Notwendigkeit einer Erweiterung (Verspottung) zu verhindern, und ich wünschte, der Entwickler hätte nicht angenommen, dass ich die Klasse niemals erweitern müsste.
quelle
final
sollte dies jedoch die Standardeinstellung sein.Für uns war es, weil wir Mockito-Inline vom Koin-Test ausgeschlossen haben. Ein Gradle-Modul benötigte dies tatsächlich und schlug aus gutem Grund nur bei Release-Builds fehl (Debug-Builds in der IDE funktionierten) :-P
quelle
Für die letzte Klasse fügen Sie unten hinzu, um statisch oder nicht statisch zu verspotten und aufzurufen.
1- diese Ebene in der Klasse hinzufügen @SuppressStatucInitializationFor (Wert = {Klassenname mit Paket})
2- PowerMockito.mockStatic (ClassName.class) wird Klasse verspotten
3- dann verwenden , wenn Anweisung Mock - Objekt zurück , wenn Methode dieser Klasse aufgerufen wird .
Genießen
quelle
Ich habe nicht versucht, endgültig, aber für private, mit Reflexion entfernen Sie den Modifikator funktioniert! weiter geprüft haben, funktioniert es nicht für final.
quelle