Написание юнит-тестов на неизменяемость

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

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

Например, предположим, что я разработал класс, скажем, Digit, и у него есть метод под названием add. Итак, тестовый пример, который я пишу,

@Test
public void test_add(){
    Digit zero = Digit.getInstance(); //ignore why i am using getinstance here

    Digit result = zero.add(new Random().nextInt());

    assertNotEqual (zero, result); //there is no equal method overridden in Digit class
}

Я предполагаю, что assertNotEqual проверит Справка двух объектов (zero и result). Если обе ссылки различны, это означает, что операция, выполненная с объектом zero, вернула новый объект, а не старый.

Имеет ли это смысл?

1. Лично, если ваши методы настолько просты, я бы не стал их тестировать. Реальный пример может помочь. 2. Если nextInt() возвращает 0, может быть, нецелесообразно возвращать исходный объект? Я думаю, что этот тест может быть подвержен периодическим сбоям.

markspace 29.05.2018 01:24

@markspace благодарит за вклад. Возможно, я не смогу поделиться исходным кодом, поскольку он связан с заданием, над которым я работаю. Фактический код касается реализации структуры данных и их основных операций. @StephenC - конечно, вместо использования equals я могу просто использовать оператор ==. Но вопрос остается прежним. это правильный подход к проверке неизменяемости.

Em Ae 29.05.2018 01:31

Не используйте случайность в модульном тесте. Нет никакой ценности. Используйте константы.

John Kugelman 29.05.2018 01:54
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
3
144
2

Ответы 2

My assumption here is that assertNotEqual will test the reference of two objects

Не предполагайте. Прочтите javadoc! Он говорит:

Asserts that two objects are not equals. If they are, an AssertionError without a message is thrown. If unexpected and actual are null, they are considered equal.

Другими словами, это использование стандартного метода проверки равенства Object::equals(Object). Это будет использовать сравнение == только в том случае, если это то, что делает соответствующий метод equals(Object) под капотом.


Чтобы ответить на ваш вопрос, тестирование zero == result не является ни необходимым, ни достаточным тестом на неизменность.

  • zero плюс какое-то случайное целое число может быть нулем
  • Тот факт, что zero - это == или не == - result, не доказывает, что состояние объекта zero не изменилось.

На самом деле, я не думаю, что существует действительный тест на неизменяемость в общем смысле. Свойство неизменяемости описывает то, что происходит внутри границы абстракции вашего класса Digit. Если вы относитесь к Digit как к истинному черному ящику, вы не можете предполагать, что сможете обнаружить изменения внутри ящика.

Единственный действенный способ проверить (истинную) неизменяемость - это объединить тестирование с (уверенным) знанием того, что происходит «внутри коробки»; т.е. проверка кода вашего класса Digit и тестирование методом белого ящика.

Другой альтернативный вариант - определить, что вы подразумеваете под «неизменяемостью» в терминах определенных внешне видимых атрибутов Digit; например что возвращает toString(). (Но с этим подходом тоже есть проблемы ...)

как бы вы в этом случае проводили тестирование методом белого ящика?

Em Ae 29.05.2018 02:16

Я бы начал с рассмотрения класса Digit.

Stephen C 29.05.2018 02:28

assertEquals / assertNotEquals проверка на равенство с использованием метода объектов equals. Он похож на assertTrue(expected.equals(actual)). Если равенство не переопределено, он проверит ссылки на объект (хэш-код), но я бы не стал на это полагаться, поскольку это может нарушить ваш тест, если вы в конечном итоге реализуете метод equals.

Если вы хотите проверить, совпадают ли объекты (или нет), используйте assertSame / assertNoSame, которые проверяют на равенство ссылок, аналогично assertTrue(expected == actual).

Но проверка неизменяемости - это не только проверка того, возвращает ли какая-либо модифицирующая операция новый экземпляр, но и проверка того, что исходный объект все еще не изменился!

Один из способов сделать это - создать эталонный объект (или клон) исходного объекта и Кроме того проверить, что исходный объект все еще равен эталонному объекту после вызова add.

@Test
public void test_add(){
    Digit zero = Digit.getInstance();

    Digit goldenMaster = zero.clone(); //if clone is implemented
    //or this
    Digit goldenMaster = Digit.getInstance(); 

    Digit result = zero.add(new Random().nextInt());

    assertNotSame (zero, result); //use check for reference
    assertEquals(goldenMaster, zero); //check the original object is still unmodified
}

Но это, в свою очередь, требует, чтобы вы правильно реализовали равенство.

Другие вопросы по теме