2010-01-26 5 views
14

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

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

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

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

Спасибо!

+5

Сначала напишите тесты JUnit? Откладывая их на запись (или вообще не записывая их), вы можете потратить больше времени на исправление ошибок, чем написание тестов. –

+0

Я обнаружил, что автоматическое рефакторинг с использованием IDE, такой как eclipse или intellij, почти всегда даст вам код, который является точно такой же семантикой, как и оригинал, с очень небольшим количеством редких случаев, когда он идет не так (в основном в вызовы Class.forname(), а иногда Intellij запутывается и создает код, который не компилируется). – Chii

ответ

34

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

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

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

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

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

+1

Прохладный совет. +1. –

+0

+1 Большой совет. Множество мелких мелких коммитов. Получите его в проверяемом состоянии, а затем напишите модульные тесты и продолжите. – Timothy

+0

+1 aka Refactor Low-Hanging Fruit: http://c2.com/cgi/wiki?RefactorLowHangingFruit –

4

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

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

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

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

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

2

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

+0

Что делать, если ваши модульные тесты не подходят? Например, они не покрывают какой-либо крайний кейс? Или какой-то другой программист пришел в это время и добавил функцию без единичного теста? Как вы убедитесь, что вы не нарушите такую ​​функциональность? – lexicalscope

8

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

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

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

5

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

Строго говоря, рефакторинга представляет собой набор хорошо известной трансформации, которые были доказаны для сохранения семантики коды. См. Refactoring Object-Oriented Frameworks. Все остальное следует называть re-engineering, но я согласен, что оба они используются взаимозаменяемо.

Рассуждение о сохранении семантики сложно и является открытой темой для исследований. См., Например, Formalising Behaviour Preserving Program Transformations.

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

3

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

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

1

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

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

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

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

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

1

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

Дополнительная информация доступна here.

1

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

1

Я немного удивлен, что до сих пор никто не упомянул книгу Working Effectively with Legacy Code, автор Michael Feathers. Он занимается этой конкретной ситуацией, с множеством практических советов, на разных языках. Я рекомендую его всем, кто занимается старыми проектами.

Смежные вопросы