Лучшие практики для модификации устаревшего кода с помощью автоматических тестов

22

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

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

tjansson
источник
1
Шаг 1: Поиск переполнения стека. Вопрос был задан. Много, много раз.
С.Лотт

Ответы:

20

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

Затем несколько заметок:

  • У вас есть точная спецификация / контракт для интерфейса, или у вас есть только существующая реализация как «спецификация»? В первом случае проще сделать полную переписку с нуля, во втором - трудно или невозможно.
  • если вы хотите переопределить интерфейс, самый полезный способ потратить ресурсы на тестирование - это писать тесты только для интерфейса. Конечно, это не квалифицируется как модульное тестирование в строгом смысле, скорее функциональное / приемочное тестирование, но я не пурист :-) Однако эти тесты можно использовать повторно и позволяют вам напрямую сравнивать результаты двух реализаций бок о бок ,
  • В целом, я бы предпочел рефакторинг существующего кода, а не переписывание с нуля, если только он полностью не поддерживается. (Но в этом случае, как вы собираетесь писать юнит-тесты против него?) Проверьте этот пост от Джоэла для более подробного обсуждения этой темы. Создав набор приемочных тестов для интерфейса, вы получаете тонкую, но полезную сеть безопасности, с которой вы можете осторожно начать рефакторинг существующего кода, чтобы сделать его модульно тестируемым (используя идеи из книги Фезерса).
Петер Тёрёк
источник
Я бы +3 это, если бы мог. WELC - это очень важный материал для чтения, и он определенно
нуждается
Один второстепенный комментарий ко 2-му пункту заключается в том, что для устаревших систем тестирование должно проводиться в соответствии с настройкой тестирования характеристик . Таким образом, точно фиксируйте текущее поведение программного обеспечения и воздерживайтесь от изменения поведения, даже если некоторые результаты теста кажутся странными или неприемлемыми в соответствии с настройкой модульного тестирования. (Кстати, эта идея также исходит от автора WELC.)
Rwong
@ rwong, действительно. Без подробной спецификации или знающего владельца продукта разработчик не может решить, является ли конкретное поведение программы а) преднамеренным и обязательным, б) непреднамеренным, но в настоящее время пользователи зависят от него, в) ошибкой, которая на самом деле наносит вред пользователям, г) ошибка совершенно незаметна до сих пор. В первых двух случаях «исправление» фактически повредило бы пользователей, а в последнем случае исправление - хотя и теоретически правильное - не принесло бы видимой пользы.
Петер Тёрёк
4

Лучший метод - это метод Микадо. http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ Это всего лишь обобщение простой техники, но это единственный известный мне способ начать улучшать качество кода в большой базе кода. без принятия ненужных рисков.

WEWLC - также очень хорошая книга об этом, но написанный на C ++ не всегда полезен с кодом Java или Ruby.

Uberto
источник
2

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

Если возможно (есть ли у вас время / деньги), одним из способов продвижения вперед будет рефакторинг кода в более тестируемые модули.

Ozz
источник
1

Я хотел бы добавить одну ссылку . Есть несколько примеров не так легко тестируемых реализаций, которые были преобразованы в более дружественный к xUnit код. Что касается общего подхода, попробуйте попробовать уже упомянутые ссылки (пост Джоэла, Работа с устаревшим кодом

yoosiba
источник