Утверждают, что два Java-бина эквивалентны - PullRequest
13 голосов
/ 16 ноября 2009

Этот вопрос близок, но все еще не то, что я хочу. Я хотел бы в общих чертах утверждать, что два объекта бина эквивалентны. В противном случае я хотел бы получить подробное сообщение об ошибке, объясняющее разницу вместо логического «равно» или «не равно».

Ответы [ 12 ]

14 голосов
/ 23 марта 2015
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));
}
13 голосов
/ 12 февраля 2013

Я рекомендую использовать unitils библиотека:

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

Смотри также:

4 голосов
/ 16 ноября 2009

Вы можете использовать Commons Lang ToStringBuilder, чтобы преобразовать их оба в удобочитаемые строки, а затем использовать assertEquals() в обеих строках.

Если вам нравится XML, вы можете использовать java.lang.XMLEncoder , чтобы превратить ваш компонент в XML, а затем сравнить два XML-документа.

Лично я предпочитаю ToStringBuilder, поскольку он дает вам больший контроль над форматированием и позволяет выполнять такие вещи, как сортировка элементов в наборе, чтобы избежать ложных негативов.

Я предлагаю поместить каждое поле компонента в отдельную строку, чтобы их было намного проще сравнивать ( подробности см. В моем блоге ).

1 голос
/ 09 марта 2016

Вы можете установить все поля следующим образом:

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 голос
/ 20 мая 2015

Для модульного тестирования это можно сделать с помощью JUnit и Mockito, используя ReflectionEquals. При реализации следующим образом он будет выгружать JSON-представления объектов, когда какие-либо поля не равны, что облегчает поиск проблемной разницы.

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

assertThat("Validating field equivalence of objects", expectedObjectValues, new ReflectionEquals(actualObjectValues));
1 голос
/ 16 ноября 2009

Я думаю, что наиболее общий подход состоит в том, чтобы отразить членов бина и проверить их на равенство один за другим. Общий язык EqualsBuilder - хорошее начало, и его не должно быть сложным, чтобы адаптировать его (на уровне источника) к вашим требованиям (сообщая о различиях вместо того, чтобы возвращать равный результат).

0 голосов
/ 30 августа 2016

Библиотека xtendbeans может представлять интерес в этом контексте:

AssertBeans.assertEqualBeans(expectedBean, actualBean);

Это производит JUnit ComparisonFailure а-ля:

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'
       ]
  ]

Вы также можете использовать его только для получения текстового представления для других целей:

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

С этой библиотекой вы можете использовать приведенный выше синтаксически действительный фрагмент кода инициализации объекта, чтобы скопировать / вставить его в (Xtend) исходный класс для expectedBean, но вам это не нужно, его вполне можно использовать без Xtend.

0 голосов
/ 16 ноября 2009

(для построения моего комментария к Andreas_D выше)

/** 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 + ">");
    }
}

Это то, что я использую, и я считаю, что оно отвечает всем основным требованиям. Делая утверждение в отражающей ToString, Eclipse выделит разницу.

В то время как Hamcrest может предложить гораздо более приятное сообщение, это требует гораздо меньше кода.

0 голосов
/ 16 ноября 2009

Я предполагаю, что оба компонента имеют одинаковый тип, и в этом случае только значения переменных-членов будут различаться в разных экземплярах компонента.

Определите класс утилит (public static final с private ctor), который называется, скажем, BeanAssertEquals. Используйте Java-отражение, чтобы получить значение каждой переменной-члена в каждом бине. Затем выполните equals () между значениями одной и той же переменной-члена в разных bean-компонентах. Если равенство не удается, укажите имя поля.

Примечание: переменные-члены, как правило, являются закрытыми, поэтому вам потребуется использовать отражение, чтобы временно изменить доступность закрытых членов.

Кроме того, в зависимости от того, насколько детализированным вы хотите, чтобы утверждение работало, вы должны учитывать следующее:

  1. Равенство переменных-членов не в классе бина, а во всех суперклассах.

  2. Равенство элементов в массивах, если переменная-член имеет тип array.

  3. Для двух значений заданного члена в компонентах вы можете использовать BeanAssertEquals.assertEquals (value1, value2) вместо value1.equals (value2).

0 голосов
/ 16 ноября 2009

Первый вопрос, который я должен спросить, если вы хотите сделать «глубокие» равные на Бобе? у него есть дочерние бобы, которые нужно проверить? Вы можете переопределить метод equals, но он возвращает только логическое значение, поэтому вы можете создать «компаратор», который может выдать исключение с сообщением о том, что не равно.

В следующих примерах я перечислил несколько способов реализации метода equals.

Если вы хотите проверить, являются ли они одним и тем же экземпляром объекта, то нормальный метод equals из Object сообщит вам.

    objectA.equals(objectB);

если вы хотите написать метод equals клиента, чтобы проверить, что все переменные-члены объекта делают их равными, то вы можете переопределить метод equals следующим образом ...

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

Последний вариант - использовать отражение java для проверки всех переменных-членов в методе equals. Это замечательно, если вы действительно хотите проверить каждую переменную-член с помощью метода bean get / set. Это не (я не думаю) позволит вам проверить частные переменные memeber, когда тестирование двух объектов одинаково. (если ваша объектная модель имеет круговую зависимость, не делайте этого, она никогда не вернется)

ПРИМЕЧАНИЕ: это не мой код, а от ...

Отражение Java равно public static логическое equals (объект bean1, объект bean2) { // Обрабатываем тривиальные случаи если (bean1 == bean2) верните истину;

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;

Единственное, что это делает, это не говорит вам причину разницы, но это может быть сделано через сообщение Log4J, когда вы найдете раздел, который не равен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...