Affirmer que deux Java beans sont équivalents

cette question est proche, mais toujours pas ce que je veux. J'aimerais affirmer de façon générique que deux objets en haricot sont équivalents. Dans le cas contraire, je voudrais un message d'erreur détaillé expliquant la différence au lieu d'un booléen "égal" ou "pas égal".

10
demandé sur Community 2009-11-16 12:27:04

12 réponses

unitils bibliothèque:

http://www.unitils.org/tutorial-reflectionassert.html

public class User {

    private long id;
    private String first;
    private String last;

    public User(long id, String first, String last) {
        this.id = id;
        this.first = first;
        this.last = last;
    }
}
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Doe");
assertReflectionEquals(user1, user2);

Voir aussi:

12
répondu gavenkoa 2017-05-23 12:17:18
import static org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs;
import static org.junit.Assert.assertThat;

@Test
public void beansAreTheSame(){
    MyDomianClass bean1 = new MyDomainClass();
    MyDomianClass bean2 = new MyDomainClass();
    //TODO - some more test logic

    assertThat(bean1, samePropertyValuesAs(bean2));
}
12
répondu Chomeh 2015-03-23 08:19:51

Vous pouvez utiliser Commons LangToStringBuilder pour convertir tous deux lisible cordes et ensuite utiliser assertEquals() sur les deux chaînes.

si vous aimez XML, vous pouvez utiliser java.lang.XMLEncoder pour transformer votre haricot en XML et ensuite comparer les deux documents XML.

Personnellement, je préfère ToStringBuilder puisqu'il vous donne plus de contrôle sur le formatage et vous permet de faire des choses comme trier les éléments dans un ensemble pour éviter false négatif.

je vous suggère de mettre chaque champ de la fève dans une ligne différente pour le rendre beaucoup plus simple de les comparer (voir mon blog pour plus de détails).

3
répondu Aaron Digulla 2009-11-16 09:41:46

je pense que l'approche la plus générique est de refléter les membres de bean et de les tester pour l'égalité un par un. La commune de lang EqualsBuilder est un bon début et cela ne devrait pas être une grosse affaire, pour l'adapter (au niveau de la source) à vos besoins (rapporter les différences au lieu de retourner le résultat égal).

1
répondu Andreas_D 2009-11-16 10:45:38

pour les tests unitaires, cela peut être fait avec JUnit et Mockito en utilisant des réflecteurs. Lors de la mise en œuvre de la manière suivante, il dumpera les représentations JSON des objets quand n'importe quels champs ne sont pas égaux ce qui rend facile de trouver la différence offensante.

import static org.junit.Assert.assertThat;
import org.mockito.internal.matchers.apachecommons.ReflectionEquals;

assertThat("Validating field equivalence of objects", expectedObjectValues, new ReflectionEquals(actualObjectValues));
1
répondu Hazok 2015-05-20 01:47:52

Vous pouvez définir tous les champs comme ceci:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
public void test_returnBean(){

    arrange();

    MyBean myBean = act();

    assertThat(myBean, allOf(hasProperty("id",          is(7L)), 
                             hasProperty("name",        is("testName1")),
                             hasProperty("description", is("testDesc1"))));
}
1
répondu borjab 2016-03-09 19:09:54

puisque vous n'avez pas aimé les réponses à la question que vous avez mentionnée, pourquoi ne pas simplement avoir un toXml méthode dans chaque haricot, les transformer en un fichier xml et ensuite utiliser xmlUnit pour comparer.

Vous pouvez obtenir plus d'informations sur la comparaison des fichiers xml ici:

meilleure façon de comparer 2 documents XML en Java

0
répondu James Black 2017-05-23 11:54:22

vous n'êtes pas vraiment affirmer l'égalité, plus faire un "diff". De toute évidence, la signification de "même" dépend d'une logique particulière pour chaque type, et la représentation de la différence peut également varier. Une différence majeure entre cette exigence et un equals conventionnel() est que généralement equals() s'arrêtera dès que la première différence est vue, vous voudrez poursuivre et comparer chaque domaine.

je voudrais envisager de réutiliser certains des modèles d'equals (), mais je pense que vous aurez besoin pour écrire votre propre code.

0
répondu djna 2009-11-16 09:35:44

je suppose ici que les deux haricots sont du même type, auquel cas seules les valeurs de la variable membre différeront entre les cas de haricots.

définir une classe util (final public statique avec ctor privé) appelée, disons, BeanAssertEquals. Utilisez Java reflection pour obtenir la valeur de chaque variable membre dans chaque haricot. Puis faites un égal () entre les valeurs pour la même variable membre dans des haricots différents. Si une égalité échoue, mentionnez le nom du champ.

Remarque: membre les variables sont habituellement privées, de sorte que vous devez utiliser la réflexion pour modifier temporairement l'accessibilité des députés.

de plus, en fonction de la précision avec laquelle vous voulez que l'affirmation fonctionne, vous devriez considérer ce qui suit:

  1. égalité des variables membres non pas dans la classe des haricots, mais dans toutes les superclasses.

  2. égalité des éléments dans les tableaux, dans le cas où une variable membre est de type tableau.

  3. pour deux valeurs d'un membre donné à travers les haricots, vous pourriez envisager de faire des quals de haricots.assertEquals(valeur1, valeur2) au lieu de valeur1.equals(valeur2).

0
répondu 2009-11-16 09:44:32

la première question que je dois vous poser est, Voulez-vous faire "deep" égale sur le haricot? a-t-elle des enfants haricots qui doivent être testés? Vous pouvez outrepasser la méthode des égaux, mais cela renvoie seulement un booléen, de sorte que vous pourriez créer un 'comparateur' et qui pourrait jeter une exception avec un message sur ce qui n'était pas égal.

dans les exemples suivants, j'ai énuméré quelques façons d'implémenter la méthode equal.

si vous voulez vérifier s'ils sont sur la même instance d'objet, alors la méthode normale égale de L'objet vous le dira.

    objectA.equals(objectB);

si vous voulez écrire une méthode client égal pour vérifier que tous les membres variables d'un objet les rendent égaux, alors vous pouvez outrepasser la méthode égal comme ceci...

  /**
     * Method to check the following...
     * <br>
     * <ul>
     *    <li>getTitle</li>
     *    <li>getInitials</li>
     *    <li>getForename</li>
     *    <li>getSurname</li>
     *    <li>getSurnamePrefix</li>
     * </ul>
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj)
    {
      if (   (!compare(((ICustomer) obj).getTitle(), this.getTitle()))
          || (!compare(((ICustomer) obj).getInitials(), this.getInitials()))
          || (!compare(((ICustomer) obj).getForename(), this.getForename()))
          || (!compare(((ICustomer) obj).getSurname(), this.getSurname()))
          || (!compare(((ICustomer) obj).getSurnamePrefix(), this.getSurnamePrefix()))
          || (!compare(((ICustomer) obj).getSalutation(), this.getSalutation()))  ){
          return false;
      }
      return true;
    }

la dernière option est d'utiliser java reflection pour vérifier tous les membres variables dans la méthode equal. C'est génial si vous voulez vraiment vérifier chaque membre varible via sa méthode bean get/set. Il ne vous permettra pas (Je ne pense pas) pour vérifier privé memeber varibles lors de l'essai des deux objets sont les mêmes. (pas si votre modèle d'objet a une forme circulaire de dépendance, ne faites pas cela, il ne reviendra jamais)

NOTE: ce n'est pas mon code, il vient de...

réflexion Java égale public booléen statique égale (objet bean1, objet bean2)) { // Gérer les cas insignifiants si (bean1 = = bean2) return true;

if (bean1 == null)
return false;

if (bean2 == null)
return false;

// Get the class of one of the parameters
Class clazz = bean1.getClass();

// Make sure bean1 and bean2 are the same class
if (!clazz.equals(bean2.getClass()))
{
return false;
}

// Iterate through each field looking for differences
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
// setAccessible is great (encapsulation
// purists will disagree), setting to true
// allows reflection to have access to
// private members.
fields[i].setAccessible(true);
try
{
Object value1 = fields[i].get(bean1);
Object value2 = fields[i].get(bean2);

if ((value1 == null && value2 != null) ||
(value1 != null && value2 == null))
{
return false;
}

if (value1 != null &&
value2 != null &&
!value1.equals(value2))
{
return false;
}
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}

return true;

la seule chose à laquelle cela ne fait pas vous dire la raison de la différence, mais cela pourrait être fait via un message à Log4J quand vous trouvez une section qui n'est pas égale.

0
répondu jeff porter 2009-11-16 09:49:43

(pour construire sur mon commentaire Andreas_D au-dessus)

/** Asserts two objects are equals using a reflective equals.
 * 
 * @param message The message to display.
 * @param expected The expected result.
 * @param actual The actual result
 */
public static void assertReflectiveEquals(final String message, 
        final Object expected, final Object actual) {
    if (!EqualsBuilder.reflectionEquals(expected, actual)) {
        assertEquals(message, 
                reflectionToString(expected, ToStringStyle.SHORT_PREFIX_STYLE), 
                reflectionToString(actual, ToStringStyle.SHORT_PREFIX_STYLE));
        fail(message + "expected: <" + expected + ">  actual: <" + actual + ">");
    }
}

C'est ce que j'utilise, et je crois qu'il répond à toutes les exigences de base. En faisant l'affirmation sur le ToString réfléchissant puis Eclipse mettra en évidence la différence.

Hamcrest peut offrir beaucoup plus de message, cela implique beaucoup moins de code.

0
répondu Michael Lloyd Lee mlk 2017-05-23 11:54:22

xtendbeans bibliothèque pourrait être intéressant dans ce contexte:

AssertBeans.assertEqualBeans(expectedBean, actualBean);

Cela produit un JUnit ComparisonFailure à la:

expected: 
    new Person => [
        firstName = 'Homer'
        lastName = 'Simpson'
        address = new Address => [
          street = '742 Evergreen Terrace'
          city = 'SpringField'
       ]
  ]
but was:
    new Person => [
        firstName = 'Marge'
        lastName = 'Simpson'
        address = new Address => [
          street = '742 Evergreen Terrace Road'
          city = 'SpringField'
       ]
  ]

Vous pouvez également l'utiliser juste pour obtenir la représentation textuelle à d'autres fins:

String beanAsLiteralText = new XtendBeanGenerator().getExpression(yourBean)

avec cette bibliothèque, vous pouvez utiliser le fragment de code d'initialisation d'objet ci-dessus valide sur le plan syntaxique pour le copier/coller dans une classe source (Xtend) pour le expectedBean, mais vous n'en avez pas, il peut parfaitement être utilisé sans Xtend.

-1
répondu vorburger 2016-08-30 08:53:41