2009-10-09 2 views
67

Вы когда-нибудь добавляли модульные тесты после факта к устаревшему коду? Насколько сложным был код и как сложно заглушить и издеваться над всем? Был ли конечный результат стоящим?Добавление модульных тестов к устаревшему коду

+4

Я проверю «Эффективно работать с устаревшим кодом». Надеюсь, это даст мне несколько хороших указателей на то, как писать обертки для всех этих статических зависимостей! – BuckeyeSoftwareGuy

+0

Взгляните на [Rhino Mocking и TDD с устаревшим кодом] (http://stackoverflow.com/questions/3519993/rhino-mocking-and-tdd-with-legacy-code/21612055#21612055) – Lijo

ответ

50

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

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

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

Нет простого способа сделать это.

Этот вопрос может помочь с дополнительными предложениями. How do you introduce unit testing into a large, legacy (C/C++) codebase?

+7

+1 для постепенного добавления тестов. – TrueWill

4

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

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

+0

Я начал создавать блок тесты для устаревшего кода, над которым я работал. Однако я понял, что я пишу интеграционные тесты, а не модульные тесты, потому что я создаю фактические данные и вставляю их в базу данных. Я не вижу способа создания чистых mocks и заглушек для этого устаревшего кода, потому что он вообще не структурирован для тестирования. –

8

Да, и это вообще больно. Мне часто приходилось писать интеграционные тесты.

В книге The Art of Unit Testing есть несколько полезных советов по этому вопросу. Он также рекомендует книгу Working Effectively with Legacy Code; Я еще не прочитал последнее, но это в моем стеке.

EDIT: Да, даже минимальное покрытие кода было полезным. Это дало мне уверенность и безопасность для рефакторинга кода.

EDIT: Я действительно прочитал «Эффективно работаю с устаревшим кодом», и это отлично.

+3

+1 для «Эффективной работы с устаревшим кодом»: полный большой совет; на самом деле это стоит того, чтобы читать даже в средах с зеленым полем, так же, как отличный ресурс по созданию кода для проверки. – itowlson

+1

+1 для идеи замены модульных тестов с интеграционными тестами. При правильном издевательстве первые были достаточно хороши, довольно часто – DVK

36

Книга Майкла Перса «Эффективная работа с устаревшим кодом» - это целая книга, посвященная этой теме. Майкл утверждает, что часто бывает сложно вводить тесты для устаревшего кода, поскольку он не структурирован для проверки. То, что я выбрал из книги, - это несколько паттернов, названных «Функции Sprout» и «Sprout classes». Функция прорастания - это та, которая инкапсулирует изменения, которые необходимо внести в код. Затем вы тестируете только эти функции. Класс sprout - это та же идея, за исключением того, что новая функциональность содержится в классе.

5

Один из вариантов тестирования модулей, также представленный в разделе «Эффективная работа с устаревшим кодом» - characterization tests. У меня были интересные результаты с такими тестами. Они легче настраиваются, чем модульные тесты, поскольку вы проверяете их с точки, чем можно протестировать (называемый шов). Недостаток заключается в том, что при неудачном тестировании вы не имеете никакого намека на местоположение проблемы, поскольку тестируемая область может быть намного больше, чем при модульных тестах. Здесь помогает журнал.


Единичный испытательный каркас, такой как семейство xUnit, может использоваться для написания тестов характеристик.

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

Процесс похож как TDD один ,:

  • написать тест для части кода
  • выполнить его - не в состоянии
  • фиксируют испытание от наблюдаемого поведения кода
  • выполнить его - передать
  • повтор

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

Очевидно, что риск зависит от охвата тестов характеристик.

4

Взгляните на бесплатную библиотеку утилиты для тестирования модулей с открытым исходным кодом, ApprovalTests. Если вы являетесь разработчиком .NET, создатель Llewellyn Falco сделал series of videos, показывая, как он использует ApprovedTests для улучшения модульного тестирования как для нового, так и для устаревшего кода.

1

Я говорил некоторое время назад об идее обращенных испытаний Pyramid в унаследованный код на XPDays http://xpdays.com.ua/archive/xp-days-ukraine-2012/materials/legacy-code/

Эта презентация должна ответить на вопрос, почему это так важно иногда начинать с интеграции/функционального или даже высокого уровня приемочные испытания при работе с устаревшим кодом. А затем медленно, шаг за шагом вводя модульные тесты. Нет примеров кода - извините, но вы можете найти их в книге Михаэля Перса «Эффективно работать с Legacy Code».

Также вы можете проверить Legacy Code Retreat http://www.jbrains.ca/legacy-code-retreat и посмотреть эту встречу в своем районе.

5

Посмотрите также на новый подход в области тестирования устаревшего кода - Asis project, он вдохновлен проектом ApprovalTests и разделяет его ключевые понятия.

Как уже упоминалось о ApprovalTests подходе в this article:

Часто у вас есть огромное наследство код проекта, в котором у вас нет тестов на всех, но вы должны изменить код, чтобы реализовать новую функцию, или рефакторинг , Интересная вещь о устаревшем коде - это работает! Он работает годами, независимо от того, как это написано. И это очень хорошее преимущество этого кода. С одобрениями, только с одним тестом вы можете получить все возможные выходы (HTML, XML, JSON, SQL или любой другой вывод, который он мог бы ) и одобрить, потому что вы знаете - это работает! После того, как вы заполните таким тестом и одобрили результат, вы действительно намного безопаснее с рефакторингом , так как теперь вы «заблокировали» все существующее поведение.

Инструмент Asis предназначен, в частности, для сохранения устаревшего кода путем автоматического создания и запуска тестов характеристик.

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

+0

Как у этого не больше болей? Если репо делает то, что он утверждает, это должен быть выбранный ответ. –

+0

Имеет ли это дело с побочными эффектами в функции, кстати? Даже можно решить эту проблему? –