Angenommen, ich habe eine Klasse ohne equals () -Methode, für die die Quelle nicht vorhanden ist. Ich möchte die Gleichheit in zwei Fällen dieser Klasse behaupten.
Ich kann mehrere Behauptungen aufstellen:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
Ich mag diese Lösung nicht, weil ich nicht das vollständige Gleichheitsbild bekomme, wenn eine frühe Behauptung fehlschlägt.
Ich kann manuell manuell vergleichen und das Ergebnis verfolgen:
String errorStr = "";
if(!obj1.getFieldA().equals(obj2.getFieldA())) {
errorStr += "expected: " + obj1.getFieldA() + ", actual: " + obj2.getFieldA() + "\n";
}
if(!obj1.getFieldB().equals(obj2.getFieldB())) {
errorStr += "expected: " + obj1.getFieldB() + ", actual: " + obj2.getFieldB() + "\n";
}
...
assertEquals("", errorStr);
Dies gibt mir das vollständige Gleichheitsbild, ist aber klobig (und ich habe mögliche Nullprobleme nicht einmal berücksichtigt). Eine dritte Option ist die Verwendung von Comparator, aber compareTo () sagt mir nicht, welche Felder nicht gleich sind.
Gibt es eine bessere Methode, um das, was ich will, aus dem Objekt herauszuholen, ohne dass Unterklassen und Überschreibungen gleich sind (ugh)?
quelle
equal
sagt eine Implementierung der Methode nur aus, ob zwei Instanzen gleich sind, und es ist uns egal, warum die Intanzen nicht gleich sind.Object
haben eineequals
Methode, Sie meinten wahrscheinlich keine überschriebene Gleichheitsmethode.Antworten:
Mockito bietet einen Reflection-Matcher:
Für die neueste Version von Mockito verwenden Sie:
Für ältere Versionen verwenden Sie:
quelle
org.mockito.internal.matchers.apachecommons
. Mockito-Dokumente geben Folgendes an:org.mockito.internal
-> "Interne Klassen, die nicht von Clients verwendet werden dürfen." Damit setzen Sie Ihr Projekt einem Risiko aus. Dies kann sich in jeder Mockito-Version ändern. Lesen Sie hier: site.mockito.org/mockito/docs/current/overview-summary.htmlMockito.refEq()
stattdessen.Mockito.refEq()
schlägt fehl, wenn die Objekte keine ID gesetzt haben = (refEq
schlägt dies fehl zu vergleichen, da die Hashcode-Methode die Objekte nicht vergleichen kann.Hier gibt es viele richtige Antworten, aber ich möchte auch meine Version hinzufügen. Dies basiert auf Assertj.
UPDATE: In assertj v3.13.2 ist diese Methode veraltet, wie Woodz im Kommentar ausgeführt hat. Aktuelle Empfehlung ist
quelle
usingRecursiveComparison()
mitisEqualTo()
, so dass die LinieassertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
Ich implementiere diesen Anwendungsfall im Allgemeinen mit org.apache.commons.lang3.builder.EqualsBuilder
quelle
Ich weiß, dass es ein bisschen alt ist, aber ich hoffe, es hilft.
Ich habe das gleiche Problem wie Sie, daher habe ich nach einer Untersuchung nur wenige ähnliche Fragen gefunden wie diese, und nachdem ich die Lösung gefunden habe, beantworte ich dasselbe in diesen, da ich dachte, es könnte anderen helfen.
Die am häufigsten gewählte Antwort (nicht die vom Autor ausgewählte) auf diese ähnliche Frage ist die für Sie am besten geeignete Lösung.
Grundsätzlich besteht es aus der Verwendung der Bibliothek Unitils .
Dies ist die Verwendung:
Was auch dann passieren wird, wenn die Klasse
User
nicht implementiertequals()
. Weitere Beispiele und eine wirklich coole Behauptung finden SieassertLenientEquals
in ihrem Tutorial .quelle
Unitils
gestorben zu sein, siehe stackoverflow.com/questions/34658067/is-unitils-project-alive .Sie können Apache commons lang ReflectionToStringBuilder verwenden
Sie können entweder die Attribute, die Sie testen möchten, einzeln angeben oder besser diejenigen ausschließen, die Sie nicht möchten:
Anschließend vergleichen Sie die beiden Zeichenfolgen wie gewohnt. Für den Punkt, dass die Reflexion langsam ist, gehe ich davon aus, dass dies nur zum Testen dient und daher nicht so wichtig sein sollte.
quelle
Wenn Sie hamcrest für Ihre Asserts (assertThat) verwenden und keine zusätzlichen Testbibliotheken abrufen möchten, können Sie
SamePropertyValuesAs.samePropertyValuesAs
Elemente aktivieren, für die keine überschriebene Gleichheitsmethode vorhanden ist.Der Vorteil ist, dass Sie kein weiteres Testframework aufrufen müssen und es einen nützlichen Fehler gibt, wenn die Zusicherung fehlschlägt (
expected: field=<value> but was field=<something else>
), anstattexpected: true but was false
wenn Sie so etwas verwendenEqualsBuilder.reflectionEquals()
.Der Nachteil ist, dass es sich um einen flachen Vergleich handelt und es keine Option zum Ausschließen von Feldern gibt (wie in EqualsBuilder), sodass Sie verschachtelte Objekte umgehen müssen (z. B. entfernen und unabhängig voneinander vergleichen).
I'm besten fall:
Hässlicher Fall:
Also, nimm dein Gift. Zusätzliches Framework (z. B. Unitils), nicht hilfreicher Fehler (z. B. EqualsBuilder) oder flacher Vergleich (Hamcrest).
quelle
Die Bibliothek Hamcrest 1.3 Utility Matchers verfügt über einen speziellen Matcher, der Reflexion anstelle von Gleichheit verwendet.
quelle
Einige der Reflexionsvergleichsmethoden sind flach
Eine andere Möglichkeit besteht darin, das Objekt in einen JSON zu konvertieren und die Zeichenfolgen zu vergleichen.
quelle
Mit Shazamcrest können Sie Folgendes tun:
quelle
reflectEquals
zurück,false
wenn die Objekte unterschiedliche Referenzen haben.Feld für Feld vergleichen:
quelle
AssertJ-Assertions können verwendet werden, um die Werte zu vergleichen, ohne dass die
#equals
Methode ordnungsgemäß überschrieben wird, z.quelle
Da diese Frage alt ist, werde ich einen anderen modernen Ansatz mit JUnit 5 vorschlagen.
Mit JUnit 5 gibt es eine Methode namens, mit
Assertions.assertAll()
der Sie alle Zusicherungen in Ihrem Test zusammenfassen können. Sie führt jede aus und gibt am Ende alle fehlgeschlagenen Zusicherungen aus. Dies bedeutet, dass Zusicherungen, die zuerst fehlschlagen, die Ausführung letzterer Zusicherungen nicht stoppen.quelle
Sie können Reflektion verwenden, um den vollständigen Gleichheitstest zu "automatisieren". Sie können den Gleichheits-Tracking-Code implementieren, den Sie für ein einzelnes Feld geschrieben haben, und dann mithilfe von Reflection diesen Test für alle Felder im Objekt ausführen.
quelle
Dies ist eine generische Vergleichsmethode, bei der zwei Objekte derselben Klasse auf ihre Werte für die Felder verglichen werden (beachten Sie, dass auf diese Objekte mit der Methode get zugegriffen werden kann).
quelle
Ich bin auf einen sehr ähnlichen Fall gestoßen.
Ich wollte auf einem Test vergleichen , dass ein Objekt als ein anderes die gleichen Attributwerte hatte, aber Methoden wie
is()
,refEq()
usw. nicht funktionieren würden , aus Gründen , wie mein Objekt einen Nullwert in seinem mitid
Attribute.Das war also die Lösung, die ich gefunden habe (nun, ein Mitarbeiter hat sie gefunden):
Wenn der von erhaltene Wert
reflectionCompare
0 ist, bedeutet dies, dass sie gleich sind. Wenn es -1 oder 1 ist, unterscheiden sie sich in einigen Attributen.quelle
Im allgemeinen Fall können Sie mit AssertJ eine benutzerdefinierte Komparatorstrategie erstellen:
Verwenden einer benutzerdefinierten Vergleichsstrategie in Zusicherungen
Beispiele anführen
quelle
Ich hatte genau das gleiche Rätsel beim Unit-Test einer Android-App, und die einfachste Lösung, die ich gefunden habe, bestand darin, einfach Gson zu verwenden, um meine tatsächlichen und erwarteten Wertobjekte in Zeichenfolgen umzuwandeln
json
und als Zeichenfolgen zu vergleichen.Die Vorteile dieses über manuell zu vergleichen Feld- für -Feld ist , dass Sie vergleichen alle Ihre Felder, also auch wenn Sie später auf ein neues Feld , um es Ihre Klasse hinzufügen , wird automatisch geprüft erhalten, im Vergleich zu , wenn Sie ein Bündel wurden mit
assertEquals()
auf Alle Felder, die dann aktualisiert werden müssten, wenn Sie Ihrer Klasse weitere Felder hinzufügen.jUnit zeigt auch die Zeichenfolgen für Sie an, sodass Sie direkt sehen können, wo sie sich unterscheiden. Ich bin mir nicht sicher, wie zuverlässig die Feldreihenfolge
Gson
ist, dies könnte jedoch ein potenzielles Problem sein.quelle
Ich habe alle Antworten ausprobiert und nichts hat wirklich für mich funktioniert.
Also habe ich meine eigene Methode erstellt, die einfache Java-Objekte vergleicht, ohne tief in verschachtelte Strukturen einzudringen ...
Die Methode gibt null zurück, wenn alle Felder übereinstimmen oder Zeichenfolgen enthalten, die nicht übereinstimmende Details enthalten.
Es werden nur Eigenschaften verglichen, die eine Getter-Methode haben.
Wie benutzt man
Beispielausgabe bei Nichtübereinstimmung
Die Ausgabe zeigt Eigenschaftsnamen und entsprechende Werte der verglichenen Objekte
Code (Java 8 und höher):
quelle
Als Alternative für Nur-Junit können Sie Felder auf Null setzen, bevor die Zusicherung gleich ist:
quelle
Können Sie den von Ihnen veröffentlichten Vergleichscode in eine statische Dienstprogrammmethode einfügen?
Dann können Sie diese Methode in JUnit wie folgt verwenden:
assertEquals ("Objekte sind nicht gleich", "", findDifferences (obj1, obj));
Das ist nicht klobig und gibt Ihnen vollständige Informationen über Unterschiede, falls vorhanden (durch nicht genau in der normalen Form von assertEqual, aber Sie erhalten alle Informationen, so dass es gut sein sollte).
quelle
Dies wird dem OP nicht helfen, aber es könnte allen C # -Entwicklern helfen, die hier landen ...
Wie bei Enrique veröffentlicht , sollten Sie die Methode equals überschreiben.
Mein Vorschlag ist, keine Unterklasse zu verwenden. Verwenden Sie eine Teilklasse.
Teilklassendefinitionen (MSDN)
Ihre Klasse würde also so aussehen ...
Für Java würde ich dem Vorschlag zustimmen, Reflektion zu verwenden. Denken Sie daran, dass Sie Reflexionen nach Möglichkeit vermeiden sollten. Es ist langsam, schwer zu debuggen und in Zukunft noch schwieriger zu warten, da IDEs Ihren Code durch eine Feldumbenennung oder ähnliches beschädigen könnten. Achtung!
quelle
Von Ihren Kommentaren bis zu anderen Antworten verstehe ich nicht, was Sie wollen.
Nehmen wir nur zur Diskussion an, die Klasse hat die Methode equals überschrieben.
Ihr UT sieht also ungefähr so aus:
Und du bist fertig. Darüber hinaus können Sie nicht das "vollständige Gleichheitsbild" erhalten, wenn die Behauptung fehlschlägt.
Soweit ich weiß, sagen Sie, dass Sie sich nicht dafür interessieren würden, selbst wenn der Typ gleich überschreiben würde, da Sie das "vollständige Gleichheitsbild" erhalten möchten. Es macht also auch keinen Sinn, Gleiches zu erweitern und zu überschreiben.
Sie müssen also Optionen haben: entweder Eigenschaft für Eigenschaft vergleichen, mithilfe von Reflexion oder fest codierten Prüfungen, ich würde letztere vorschlagen. Oder: Vergleichen Sie lesbare Darstellungen dieser Objekte.
Sie können beispielsweise eine Hilfsklasse erstellen, die den Typ, den Sie vergleichen möchten, mit einem XML-Dokument serialisiert und dann das resultierende XML vergleicht! In diesem Fall können Sie visuell sehen, was genau gleich ist und was nicht.
Dieser Ansatz gibt Ihnen die Möglichkeit, das Gesamtbild zu betrachten, ist jedoch auch relativ umständlich (und zunächst ein wenig fehleranfällig).
quelle
Sie können die equals-Methode der Klasse wie folgt überschreiben:
Wenn Sie zwei Objekte aus einer Klasse vergleichen möchten, müssen Sie die Methode equals und die Hash-Code-Methode auf irgendeine Weise implementieren
quelle