Как проверить, что Рефакторинг равен исходному коду

Я работаю с устаревшим java-кодом без каких-либо Unit-Tests. Для работы с проектом необходимо реорганизовать многие классы.

Многие рефакторинги могут выполняться с помощью eclipse, и я делаю это вручную. После некоторого рефакторинга я рассматриваю diff для cvs-HEAD, но я не уверен, что все на 100% правильное.

Вопрос: Как я могу проверить рефакторинг, математически идентичный предыдущей версии? Я хочу, чтобы был инструмент, но я также принимаю "основные человеческие алгоритмы" в качестве решений.

Я знаю: "Запустите JUnit-Tests" - лучший ответ, но, к сожалению, в моем проекте нет.

Спасибо!

Ответ 1

В разделе TDD By Example" существует конкретный раздел, в котором говорится об этом. Проблема в том, что вам нужны модульные тесты для рефакторинга, но сложный код обычно не поддается тестированию. Таким образом, вы хотите реорганизовать, чтобы сделать его проверяемым. Цикл.

Поэтому лучшая стратегия такова:

Сделайте небольшие шаги рефакторинга. Когда шаги малы, человеку легче убедиться, что общее поведение не повреждено. Выбирайте только рефакторинги, повышающие тестируемость. Это ваша ближайшая цель. Не думайте о поддержке будущей функциональности (или чего-то подобного). Просто подумайте о том, "как я могу позволить unit test проверить этот метод/класс".

Как только метод/класс станет тестируемым, напишите ему единичные тесты.

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

Ответ 2

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

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

Если это графический интерфейс, я надеюсь, что он имеет разделение MVC, поэтому вы можете протестировать модель отдельно, иначе вы можете застрять.

Ответ 3

Вопрос: как я могу проверить рефакторинг, то есть математический идентичны предыдущей версии? я Хотелось бы иметь инструмент, но я тоже принять "основные человеческие алгоритмы" как решения.

Строго говоря, рефакторинг - это набор хорошо известных преобразований, доказавших сохранение семантики кода. См. Рефакторинг объектно-ориентированных платформ. Все остальное следует называть реорганизацией, но я согласен, что оба они используются взаимозаменяемо.

Рассуждение о сохранении семантики является трудным и является открытой темой исследования. См., Например, Формирование программ, поддерживающих программные преобразования.

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

Ответ 4

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

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

возможно, это время, когда вы написали модульные тесты, которые вам так не хватает?

edit: учитывая, что вы принимаете человеческие алгоритмы - это то, что я обычно делаю. Я бы изучил код для рефакторинга и понял его семантику. Напишите хотя бы unit test или какой-то автоматизированный тест для этой части базы кода. Выполните рефакторинг, а затем проверьте, проходит ли тест. Если это так, у вас есть хороший шанс, что рефактор (*) ничего не сломал.

(*) здесь, я имею в виду, что рефакторинг меняет реализацию/алгоритм и т.д., а не просто переименовывать и перетасовывать код вокруг и делать общие строки кода в методах/базовых классах и т.д. Те, у кого вы можете почти глазное яблоко, при условии, что у вас есть хорошее понимание базы кода.

Ответ 5

Вопрос: Как я могу проверить рефакторинг, математически идентичный предыдущей версии? Хотелось бы иметь инструмент, но я также принимаю "основные человеческие алгоритмы" в качестве решений.

Я согласен с Chii в том, что это по сути невозможно. Если вам действительно нужно его реорганизовать (вместо написания адаптера для устаревшего кода, чтобы ваш новый материал был слабо связан со старым кодом), вам следует особенно заботиться о подклассах, переопределенных методах и т.д. Возможно, если вы действительно не знаете, что должен делать код, как вы можете написать для него единичные тесты? Вы можете только писать модульные тесты, чтобы убедиться, что новый код делает то, что вы предположили, что старый код сделал.

Ответ 6

Я бы сказал: "Запустите свои юнит-тесты";). Единственный вариант, по которому вы должны быть уверены, что результат тот же, является unittest. Вы можете добавить их самостоятельно, прежде чем реорганизовывать определенный код. Занимает больше времени в начале, но сэкономит вам много времени в долгосрочной перспективе.

Ответ 7

Я сделал следующее для проекта с некоторыми огромными божественными классами с необходимостью рефакторинга:

Используйте АОП для "дампа" состояния и параметров вашего объекта в начале вашего метода и в конце. Сбросьте также возвращаемое значение.

Затем запишите много сценариев с кодом, который вам нужно изменить и воспроизвести с помощью вашего реорганизованного кода.

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

Самосвал легко настраивается с помощью инструмента, такого как XStream.

Ответ 8

Я бы пошел с ответом Itay, но просто дал другой вариант.
Если вы готовы заплатить за это, есть продукт от Agitar, который автоматически генерирует тесты JUnit для существующего кода. Эти тесты являются "характеристиками" тестов, которые предназначены для тестирования кода, делает то, что в настоящее время делает. Затем, как только вы вносите изменения, вы можете видеть, что разрывы - это то, что вы хотели изменить только.

Более подробная информация доступна здесь.

Ответ 9

В теории вы можете определить набор безопасных преобразований (рефакторинг) и создать программу, которая проверяет, что программа B является результатом применения конечного подмножества этих рефакторингов к программе A. (Избегайте проблемы с остановкой, установив верхний предел). Но я боюсь, что сделать такую ​​программу гораздо сложнее, чем писать модульные тесты для программы A, что и должно быть на самом деле.

Ответ 10

Я немного удивлен, что до сих пор никто не упомянул книгу "Эффективно работая с устаревшим кодом" , автор Michael Feathers. Он занимается этой конкретной ситуацией, с множеством практических советов, на разных языках. Я рекомендую его всем, кто имеет дело с устаревшими проектами.