Правильный способ сравнить объект в модульном тесте - PullRequest
5 голосов
/ 13 июля 2011

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

Например, для данного теста:

void testExampleTest() {
    mockSession.person = new Person(firstName:'John', lastName:'Doe', middleInitial:'E')
    def model = controller.testMethod()
    ...assertions...
}

и

def testMethod = {
    Person currPerson = session.getAttribute("person")
    render(view:'view',model:[person:currPerson]
}

как мне убедиться, что объект person, который я добавил в сеанс, правильно передается в модель? Достаточно ли использовать

assertEquals( person,model['person'] )

или потому что я сам ввел объект в сеанс, имеет ли смысл использовать

assertEquals( person.firstName, model['person'].firstName )
assertEquals( person.lastName, model['person'].lastName )
assertequals( person.middleName, model['person'].middleName )

Мне кажется, что первого способа должно быть достаточно, если у объекта есть правильно определенный метод equals, но я просто хотел посмотреть, каков обычный способ.

Спасибо

Ответы [ 8 ]

4 голосов
/ 14 июля 2011

Сравнение свойств по свойствам необходимо повторять в каждом тесте - так что это хорошее старое дублирование кода, запах теста, описанный в XUnitPatterns .Лучше иметь правильный equals().

Конечно, вы можете добавить служебный метод personEquals() или даже переопределить Person.equals() во время выполнения.Для издевательского класса вам, вероятно, придется.Лично я придерживаюсь более короткого кода, который по возможности равен только одному assertEquals().

2 голосов
/ 13 июля 2011

Забавно, у меня и коллеги было подобное обсуждение сегодня.Мы пришли к выводу, что

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

Кроме того, у нас не было контроля над некоторыми классами, а в некоторых из них отсутствовал метод equals.

Мы намерены выяснить, возможно ли использовать отражение для реализации компаратора, следовательно, удалив часть скуки..

2 голосов
/ 14 июля 2011

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

1 голос
/ 14 июля 2011

В этом конкретном случае тестирование отдельных свойств - это только способ идентифицировать конкретный экземпляр объекта, и оно скрывает смысл теста.Что вас особенно волнует и должно утверждать, так это то, что model['person'] - это тот же объект, который вы изначально указали как person:

assertSame(person, model['person'])

Или с Hamcrest, который позволяет гораздо более выразительные утверждения в целом:

assertThat(model['person'], sameInstance(person))
1 голос
/ 14 июля 2011

Если равенство определено правильно, вы правы. Проблема в том, что вам, возможно, придется сначала выполнить модульный тест, если equals определен правильно (то есть он ведет себя так, как вы ожидаете).

Это может стать немного сложнее, если вы создадите макет для класса Person. В этом случае вас не волнует, работает ли equals должным образом, потому что вы хотите только проверить, правильно ли установлены / доступны некоторые атрибуты. Вот почему я предпочитаю проверять примитивные значения, если это возможно и необходимо. Я считаю, что это делает тесты также более описательными (хотя и может стать довольно многословным).

0 голосов
/ 14 июля 2011

Я использую assertSame(). Сравнение поля за полем - это гораздо больше работы, чем необходимо - вы смоделировали данные, поэтому просто подтвердите, что проверенные значения возвращаются правильно.

0 голосов
/ 14 июля 2011

В Grails каждый объект является сериализуемым, поэтому вы можете сравнить два, используя их XML-сериализации:

public void compareXML(Object a, Object b)
    ByteArrayOutputStream aBaos = new ByteArrayOutputStream();
    XMLEncoder aEncoder = new XMLEncoder(aBaos);
    aEncoder.writeObject(a);
    aEncoder.close();
    String xmlA = baos.toString();

    ByteArrayOutputStream bBaos = new ByteArrayOutputStream();
    XMLEncoder bEncoder = new XMLEncoder(bBaos);
    bEncoder.writeObject(b);
    bEncoder.close();
    String xmlB = bBaos.toString();

    assertEquals(xmlA, xmlB);
}

Если вы работаете в Eclipse, вы получите отличное текстовое сравнение двух XMLстроки, показывающие все различия.

0 голосов
/ 14 июля 2011

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

Я часто работаю с объектами базы данных, которые сравнивают только их атрибут ID.С этими объектами мне нужно проверить каждый атрибут отдельно, чтобы увидеть, равны ли они.Я написал небольшой помощник, который позволяет мне написать одно утверждение для многих свойств, например:

assertEqualProperties(person, model['person'], "firstName", "lastName", "middleName");

Этот вспомогательный метод использует отражение для доступа к атрибутам (не напрямую, я вызываю библиотеку commons-beans),В Groovy, безусловно, есть синтаксис, который не нуждается в явном отражении.Метод сообщает о первом неравном атрибуте как об ошибке теста.

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