Disons que j'ai une classe sans méthode equals (), dont je n'ai pas la source. Je veux affirmer l'égalité sur deux instances de cette classe.
Je peux faire plusieurs assertions:
assertEquals(obj1.getFieldA(), obj2.getFieldA());
assertEquals(obj1.getFieldB(), obj2.getFieldB());
assertEquals(obj1.getFieldC(), obj2.getFieldC());
...
Je n'aime pas cette solution parce que je n'obtiens pas une image complète de l'égalité si une affirmation précoce échoue.
Je peux comparer manuellement et suivre le résultat:
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);
Cela me donne une image complète de l'égalité, mais c'est maladroit (et je n'ai même pas pris en compte d'éventuels problèmes de nullité). Une troisième option consiste à utiliser Comparator, mais compareTo () ne me dira pas quels champs ont échoué à l'égalité.
Existe-t-il une meilleure pratique pour obtenir ce que je veux de l'objet, sans sous-classer ni surcharger les égaux (ugh)?
java
unit-testing
junit
Ryan Nelson
la source
la source
equal
méthode indique seulement si deux instances sont égales, et nous ne nous soucions pas de savoir pourquoi les intances ne sont pas égales.Object
ont uneequals
méthode, vous vouliez probablement dire aucune méthode égale remplacée.Réponses:
Mockito propose une réflexion-matcher:
Pour la dernière version de Mockito, utilisez:
Pour les anciennes versions, utilisez:
la source
org.mockito.internal.matchers.apachecommons
. État de la documentation Mockito:org.mockito.internal
-> "Classes internes, à ne pas utiliser par les clients." Vous exposerez votre projet à un risque en utilisant cela. Cela peut changer dans n'importe quelle version de Mockito. Lire ici: site.mockito.org/mockito/docs/current/overview-summary.htmlMockito.refEq()
plutôt.Mockito.refEq()
échoue lorsque les objets n'ont pas d'id set = (refEq
échoue à comparer car la méthode de hashcode ne peut pas comparer les objets.Il y a beaucoup de bonnes réponses ici, mais j'aimerais aussi ajouter ma version. Ceci est basé sur Assertj.
MISE À JOUR: Dans assertj v3.13.2, cette méthode est obsolète comme indiqué par Woodz dans le commentaire. La recommandation actuelle est
la source
usingRecursiveComparison()
avecisEqualTo()
, de sorte que la ligne soitassertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
J'implémente généralement ce cas d'utilisation en utilisant org.apache.commons.lang3.builder.EqualsBuilder
la source
Je sais que c'est un peu vieux, mais j'espère que ça aide.
Je rencontre le même problème que vous, donc, après enquête, j'ai trouvé peu de questions similaires à celle-ci, et, après avoir trouvé la solution, je réponds à la même chose dans celles-ci, car je pensais que cela pourrait aider les autres.
La réponse la plus votée (et non celle choisie par l'auteur) de cette question similaire , est la solution la plus appropriée pour vous.
Fondamentalement, cela consiste à utiliser la bibliothèque appelée Unitils .
Voici l'utilisation:
Ce qui passera même si la classe
User
ne s'implémente pasequals()
. Vous pouvez voir plus d'exemples et une affirmation vraiment cool appeléeassertLenientEquals
dans leur tutoriel .la source
Unitils
Semble malheureusement être mort, voir stackoverflow.com/questions/34658067/is-unitils-project-alive .Vous pouvez utiliser Apache commons lang ReflectionToStringBuilder
Vous pouvez soit spécifier les attributs que vous souhaitez tester un par un, ou mieux, exclure ceux que vous ne voulez pas:
Vous comparez ensuite les deux chaînes comme d'habitude. Pour ce qui est de la lenteur de la réflexion, je suppose que ce n'est que pour les tests, donc cela ne devrait pas être si important.
la source
Si vous utilisez hamcrest pour vos assertions (assertThat) et que vous ne voulez pas extraire de bibliothèques de test supplémentaires, vous pouvez utiliser
SamePropertyValuesAs.samePropertyValuesAs
pour assertir des éléments qui n'ont pas de méthode equals remplacée.L'avantage est que vous n'avez pas à insérer encore un autre framework de test et cela donnera une erreur utile lorsque l'assertion échoue (
expected: field=<value> but was field=<something else>
) au lieu d'expected: true but was false
utiliser quelque chose commeEqualsBuilder.reflectionEquals()
.L'inconvénient est qu'il s'agit d'une comparaison superficielle et qu'il n'y a pas d'option pour exclure des champs (comme c'est le cas dans EqualsBuilder), vous devrez donc contourner les objets imbriqués (par exemple, supprimez-les et comparez-les indépendamment).
Meilleur cas:
Affaire laide:
Alors, choisissez votre poison. Framework supplémentaire (par exemple Unitils), erreur inutile (par exemple EqualsBuilder) ou comparaison superficielle (hamcrest).
la source
La bibliothèque Hamcrest 1.3 Utility Matchers a un matcher spécial qui utilise la réflexion au lieu d'égal.
la source
Certaines des méthodes de comparaison de réflexion sont peu profondes
Une autre option consiste à convertir l'objet en json et à comparer les chaînes.
la source
En utilisant Shazamcrest , vous pouvez faire:
la source
reflectEquals
renvoiefalse
lorsque les objets ont des références différentes.Comparez champ par champ:
la source
Les assertions AssertJ peuvent être utilisées pour comparer les valeurs sans
#equals
méthode correctement remplacée, par exemple:la source
Cette question étant ancienne, je proposerai une autre approche moderne utilisant JUnit 5.
Avec JUnit 5, il existe une méthode appelée
Assertions.assertAll()
qui vous permettra de regrouper toutes les assertions de votre test, qui exécutera chacune d'elles et affichera toutes les assertions ayant échoué à la fin. Cela signifie que toutes les assertions qui échouent en premier n'arrêteront pas l'exécution des dernières assertions.la source
Vous pouvez utiliser la réflexion pour «automatiser» le test d'égalité complet. vous pouvez implémenter le code de «suivi» d'égalité que vous avez écrit pour un seul champ, puis utiliser la réflexion pour exécuter ce test sur tous les champs de l'objet.
la source
Il s'agit d'une méthode de comparaison générique, qui compare deux objets d'une même classe pour ses valeurs de champs (gardez à l'esprit que ceux-ci sont accessibles par la méthode get)
la source
Je suis tombé sur un cas très similaire.
Je voulais comparer sur un test qu'un objet avait les mêmes valeurs d'attribut comme un autre, mais des méthodes telles que
is()
,refEq()
, etc ne marcherait pas pour des raisons comme mon objet ayant une valeur nulle dans sonid
attribut.C'était donc la solution que j'ai trouvée (enfin, un collègue a trouvé):
Si la valeur obtenue à partir de
reflectionCompare
est 0, cela signifie qu'ils sont égaux. Si c'est -1 ou 1, ils diffèrent sur certains attributs.la source
Dans le cas courant avec AssertJ, vous pouvez créer une stratégie de comparaison personnalisée:
Utilisation d'une stratégie de comparaison personnalisée dans les assertions
Exemples AssertJ
la source
J'ai eu exactement la même énigme lors du test unitaire d'une application Android, et la solution la plus simple que j'ai trouvée était simplement d'utiliser Gson pour convertir mes objets de valeur réelle et attendue
json
et les comparer sous forme de chaînes.L'avantage de cela par rapport à la comparaison manuelle champ par champ est que vous comparez tous vos champs, donc même si vous ajoutez plus tard un nouveau champ à votre classe, il sera automatiquement testé, par rapport à si vous utilisiez un tas de
assertEquals()
sur tous les champs, qui devraient ensuite être mis à jour si vous ajoutez plus de champs à votre classe.jUnit affiche également les chaînes pour vous afin que vous puissiez voir directement où elles diffèrent. Vous ne savez pas à quel point la commande sur le terrain
Gson
est fiable , cela pourrait être un problème potentiel.la source
J'ai essayé toutes les réponses et rien n'a vraiment fonctionné pour moi.
J'ai donc créé ma propre méthode qui compare des objets java simples sans aller plus loin dans les structures imbriquées ...
La méthode retourne null si tous les champs correspondent ou une chaîne contenant des détails d'incompatibilité.
Seules les propriétés qui ont une méthode getter sont comparées.
Comment utiliser
Exemple de sortie en cas d'incohérence
La sortie affiche les noms de propriétés et les valeurs respectives des objets comparés
Code (Java 8 et supérieur):
la source
Comme alternative pour junit-only, vous pouvez définir les champs sur null avant l'assertion égale:
la source
Pouvez-vous mettre le code de comparaison que vous avez publié dans une méthode utilitaire statique?
Ensuite, vous pouvez utiliser cette méthode dans JUnit comme ceci:
assertEquals ("Les objets ne sont pas égaux", "", findDifferences (obj1, obj));
ce qui n'est pas maladroit et vous donne des informations complètes sur les différences, si elles existent (pas exactement sous la forme normale d'assertEqual mais vous obtenez toutes les informations, donc ça devrait être bon).
la source
Cela n'aidera pas l'OP, mais cela pourrait aider tous les développeurs C # qui se retrouvent ici ...
Comme Enrique l'a publié , vous devriez remplacer la méthode d'égalité.
Ma suggestion est de ne pas utiliser de sous-classe. Utilisez une classe partielle.
Définitions partielles de classe (MSDN)
Donc, votre classe ressemblerait à ...
Pour Java, je serais d'accord avec la suggestion d'utiliser la réflexion. N'oubliez pas que vous devez éviter d'utiliser la réflexion autant que possible. Il est lent, difficile à déboguer et encore plus difficile à maintenir dans le futur car les IDE pourraient casser votre code en renommant un champ ou quelque chose comme ça. Faites attention!
la source
De vos commentaires à d'autres réponses, je ne comprends pas ce que vous voulez.
Juste pour le plaisir de la discussion, disons que la classe a remplacé la méthode equals.
Ainsi, votre UT ressemblera à quelque chose comme:
Et vous avez terminé. De plus, vous ne pouvez pas obtenir une "image d 'égalité complète" si l' assertion échoue.
D'après ce que je comprends, vous dites que même si le type remplaçait égal à égal, cela ne vous intéresserait pas, car vous voulez obtenir une «image d'égalité complète». Il est donc inutile non plus d'étendre et de remplacer les égaux.
Vous avez donc des options: soit comparer propriété par propriété, en utilisant la réflexion ou des vérifications codées en dur, je suggérerais ce dernier. Ou: comparez les représentations lisibles par l'homme de ces objets.
Par exemple, vous pouvez créer une classe d'assistance qui sérialise le type que vous souhaitez comparer à un document XML et ensuite comparer le XML résultant! dans ce cas, vous pouvez voir visuellement ce qui est exactement égal et ce qui ne l'est pas.
Cette approche vous donnera l'opportunité d'avoir une vue d'ensemble mais elle est aussi relativement lourde (et un peu sujette aux erreurs au début).
la source
Vous pouvez remplacer la méthode equals de la classe comme:
Eh bien, si vous voulez comparer deux objets d'une classe, vous devez implémenter d'une manière ou d'une autre les égaux et la méthode de code de hachage
la source