Как проверить, что Рефакторинг равен оригинальному коду - PullRequest
14 голосов
/ 26 января 2010

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

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

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

Я знаю, «запустить свои JUnit-тесты» - лучший ответ, но, к сожалению, в моем проекте их нет.

Спасибо!

Ответы [ 10 ]

34 голосов
/ 26 января 2010

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

Поэтому лучшая стратегия выглядит следующим образом:

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

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

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

8 голосов
/ 26 января 2010

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

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

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

5 голосов
/ 26 января 2010

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

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

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

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

4 голосов
/ 26 января 2010

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

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

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

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

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

3 голосов
/ 26 января 2010

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

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

2 голосов
/ 26 января 2010

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

1 голос
/ 09 февраля 2010

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

1 голос
/ 26 января 2010

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

1 голос
/ 26 января 2010

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

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

1 голос
/ 26 января 2010

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

Используйте AOP, чтобы «сбросить» состояние объекта и параметры в начале вашего метода и в конце. Дамп возвращаемого значения тоже.

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

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

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

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