При разработке приложений Java я часто переопределяю методы объекта (обычно equals и hashCode). Я хотел бы каким-то образом систематически проверять, соблюдаю ли я контракт на методы Object для каждого из моих классов. Например, мне нужны тесты, которые утверждают, что для одинаковых объектов хэш-код также одинаков. Я использую тестовую среду JUnit, поэтому желательно какое-то решение JUnit, в котором я могу автоматически генерировать эти тесты, или какой-нибудь тестовый пример, который может каким-то образом посещать все мои классы и обеспечивать соблюдение контракта.
Я использую JDK6 и JUnit 4.4.
Хороший улов! Я отредактировал свой вопрос, чтобы включить эту информацию. :-)
код-вызов принят и закодирован (хотя первая версия может быть улучшена)
может это поможет: stackoverflow.com/questions/125100/…
Эта великолепная идея! Среда тестирования, основанная на спецификации Быстрая проверка, основана на аналогичных идеях. Может быть, это можно использовать для этого или послужить источником вдохновения?




Просто несколько первых мыслей по этому вопросу (которые могут объяснить, почему по прошествии часа до сих пор нет ответа !?;)
Когда дело доходит до решения вопроса, кажется, есть две части:
1 / получить все мои классы. Легко, вы даете имя банке, метод инициализации теста Junit:
2 / тестировать каждый объект
... и в этом кроется загвоздка: вам нужно создать экземпляр этих объектов, то есть создать два экземпляра и использовать их для тестов equals ().
Это означает, что если ваши конструкторы являются аргументами, вы должны учитывать,
Наконец, не все параметры, автоматически созданные для этого конструктора, будут иметь смысл с функциональной точки зрения, а это означает, что некоторые из этих значений не смогут создать экземпляр из-за Assert:, которое необходимо обнаружить.
Тем не менее, это кажется возможным (вы можете сделать это код-вызов, если хотите), но сначала я хочу, чтобы другие читатели StackOverflow отреагировали на эту проблему, поскольку они могут увидеть гораздо более простое решение, чем я.
Чтобы избежать проблем с комбинациями и чтобы тестовые значения соответствующие оставались близкими к фактическому коду, я бы рекомендовал определение специальной аннотации со строкой, представляющей допустимые значения для конструкторов. Он будет расположен прямо над переопределенным методом equals () одного из ваших объектов.
Затем эти значения аннотации будут прочитаны, и созданные из них экземпляры будут объединены для тестирования equals (). Это позволит снизить количество комбинаций.
Боковой узел: общий тестовый пример JUnit, конечно, проверяет, что для каждого equals () to tests существует:
Интересная мысль. Я боялся, что это может быть сложно. Возможно, сработает параметризованный тест, в котором каждый вызов принимает объект .class, за которым следуют аргументы конструктора. Возможно, я отправлю это как возможный ответ.
Я думаю, что VonC на правильном пути, но я бы даже согласился на что-то менее сложное, например, параметризованный тест, который принимает объект .class (для которого тестируются методы Object), за которым следует переменное количество аргументов конструктора. Затем вам нужно будет использовать отражение, чтобы найти конструктор, который соответствует типам для переданных аргументов, и вызвать конструктор. Этот тест предполагает, что передаваемые в него параметры создадут действительный экземпляр объекта.
Обратной стороной этого решения является то, что вам нужно «зарегистрировать» каждый класс, который вы хотите протестировать, с помощью этого тестового класса, и вы должны убедиться, что в конструктор передается действительный ввод, что не всегда бывает легко. В этом свете я сомневаюсь в том, будет ли это больше или меньше работы, чем ручное написание всех тестов для каждого класса в любом случае.
Проголосуйте, если вы думаете, что это может сработать ... оставьте комментарий, если вы хотите, чтобы я вымыл его больше (если это окажется возможным решением, я могу просто сделать это в любом случае)
эти параметры должны быть в коде самого тестируемого класса: это решит проблему «регистрации». См. Мой ответ с более подробной информацией об этой возможной реализации.
Примечание: это определенно вопрос типа "код-вызов". Если вы позволите, я добавлю «ответ сообщества» с некоторыми спецификациями: создайте один тестовый пример JUnit, который по умолчанию будет тестировать себя на предмет переопределения методов равенства и хеширования, определенных для себя: короче говоря, автономный тестовое задание.
Мне нравится идея аннотаций. Я не уверен, что такое «ответ сообщества», но это лучший способ узнать, так что дерзайте!
Право на! Вот это и есть дух;) Еще один вызов кода!
код-вызов принят и закодирован (хотя первая версия может быть улучшена)
У этой проблемы нет "простого" решения, если вы не накладываете строгие ограничения на свои классы.
Например, если вы используете несколько конструкторов для данного класса, как вы можете гарантировать, что все ваши параметры хорошо учтены в ваших методах equals / hash? Как насчет значений по умолчанию? Это вещи, которые, к сожалению, нельзя автоматизировать вслепую.
Что касается equals (), вам необходимо определить в классе, переопределив его, правильные значения для тестирования. Эти значения, вы правы, не будут автоматизированы или угаданы. Но проблема может заключаться в самом механизме тестирования. Теперь это можно автоматизировать!
public static void checkObjectIdentity(Object a1, Object a2, Object b1) {
assertEquals(a1, a2);
assertEquals(a2, a1);
assertNotSame(a1, a2);
assertEquals(a1.hashCode(), a2.hashCode());
assertFalse(a1.equals(b1));
assertFalse(a2.equals(b1));
assertFalse(b1.equals(a1));
assertFalse(b1.equals(a2));
}
Использование:
checkObjectIdentity(new Integer(3), new Integer(3), new Integer(4));
Не могу придумать ничего лучше. Добавляйте новые вызовы в checkObjectIdentity при обнаружении ошибки.
и кто создает объекты, которые будут переданы в эту функцию в качестве параметров?
Вы делаете. Не думаю, что «интересные» параметры можно придумать автоматически.
[сообщение сообщества здесь, кармы нет;)]
Вот вам еще один код-вызов:
Один java-класс, реализующий тестовый пример JUnit, с основным методом, способным запускать JUnit на самом себе!
Этот класс также:
Тестовый метод принимает параметр имени класса (здесь: это будет сам), проверьте, имеет ли класс с таким именем переопределенный метод equals () с аннотациями "интересные значения". Если это так, он построит соответствующие экземпляры (самого себя) на основе аннотаций и проверит equals ()
Это автономный тестовый класс, который определяет механизм, который может быть обобщен на любой класс с аннотированной переопределенной функцией equals ().
Пожалуйста, используйте JDK6 и JUnit4.4
Этот класс нужно скопировать-вставить в соответствующий пакет пустого java-проекта ... и просто запустить;)
Чтобы добавить еще немного мысли, в ответ Николасу (см. Комментарии):
Должны ли аннотации, представляющие потенциальные данные тестирования, никогда не быть в самом классе? ... Эй, это может быть отличный вопрос :)
> определить аннотацию, способную перечислять "интересные" значения для передачи в этот конструктор, я не уверен, что понимаю ... Аннотация добавляет логику тестирования внутри класса для тестирования? Если все в порядке, это ... некрасиво.
Куда мне обратиться, чтобы найти ответы на этот вызов? Я новичок в теме "сообщества вики" ...
@Julie ответы будут размещены на этой самой странице, так как они будут правильным ответом на ваш вопрос.
@Nicolas Я согласен, но в данном случае это может быть полезно для автоматических тестов, которые нужны Джули.
Может быть, я неправильно понимаю вопрос (и слишком CS), но не похоже, что проблема, которую вы описываете, разрешима в общем случае.
Другими словами, единственный способ, которым модульный тест может гарантировать, что метод переопределения работает на всех входах так же, как и переопределенный метод, - это попробовать его на всех входах; в случае равенства это будет означать все состояния объекта.
Я не уверен, что какая-либо текущая тестовая среда автоматически урежет и абстрагирует для вас возможности.
Это не совсем то, что мне нужно. В большинстве модульных тестов можно тестировать только с несколькими разными значениями. Я ищу модульные тесты, которые будут использовать репрезентативный набор тщательно выбранных аргументов конструктора.
У меня есть первая грубая реализация для равноправного тестирования с помощью конструктора, используя здесь только примитивные параметры. Просто скопируйте и вставьте его в файл test.MyClass.java и запустите.
Предупреждение: 1720 строк кода (0 ошибок в findbugs, 0 в «модифицированном» стиле проверки, цикломатическая сложность ниже 10 для всех функций).
Смотрите весь код по адресу: Автоматическая проверка функции равенства в классах Java с помощью аннотаций
Большое спасибо за первый удар! У меня есть это в моем списке дел, чтобы проверить это - не могу дождаться, чтобы поиграть с ним.
Пожалуйста. На данный момент он позволяет тестировать только объект с конструктором с использованием аргументов примитивный. Если вас убедил такой подход, я расширю его, включив в него конструктор с непримитивными параметрами.
Новый ответ на старый вопрос, но в мае 2011 года Гуава (ранее Google Collections) выпустила класс, который удаляет большую часть шаблонов, под названием EqualsTester. Вам по-прежнему нужно создавать свои собственные экземпляры, но он заботится о сравнении каждого объекта с самим собой, с нулевым значением, с каждым объектом в группе равенства, с каждым объектом в любой другой группе равенства и с секретным экземпляром, который не должен совпадать. Он также проверяет, что a.equals(b) подразумевает a.hashCode() == b.hashCode() во всех этих комбинациях.
Пример из Javadoc:
new EqualsTester()
.addEqualityGroup("hello", "h" + "ello")
.addEqualityGroup("world", "wor" + "ld")
.addEqualityGroup(2, 1 + 1)
.testEquals();
Какую версию junit вы используете? И, что немаловажно, в какой версии jdk вы кодируете? Другими словами, доступны ли аннотации (jdk1.5 или более) или нет (jdk1.4)?