Перейти к основному содержимому

Внедрение тестирования в существующую разработку (Legacy)

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

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

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

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

Legacy и тесты

Legacy системы сложно поддерживать и дорабатывать. Создавать для нее тесты также проблемная и затратная затея. Код сложный в поддержке также сложно покрывать тестами. Покрытие тестами заставит вас пересмотреть дизайн системы или ее компонентов, что приведет к рефакторингу, что с большой долей вероятности приведет к возникновению дефектов (багов).

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

Поэтому не тестируйте Legacy системы просто так, включайте тестирование в задачи на доработку или рефакторинг с соответствующим рабочим процессом.

В отличии от тестирования новой системы внедрение тестирования в устаревших системах будет дороже.

Стоимость внедрения

Стоимость в основном складывается из двух составляющих:

  • Стоимость внедрения тестового фреймворка в проекте: обучение, настройка CI, выработка регламентов.
  • Существующая кодовая база не готова для тестирования. Код был разработан не принимая во внимание необходимость его тестирования. Применение модульного тестирования в таком коде часто влечёт за собой улучшение существующего дизайна системы. Это не только увеличивает стоимость создания каждого теста, но также может привести к появлению новых ошибок в связи с изменением дизайна. Таким образом, добавление модульного теста к существующей кодовой базе должно сочетаться с другими мероприятиям, которые требуют изменений в тестируемом коде, как если бы вам потребовалось изменить этот фрагмент кода независимо.

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

Ниже я опиши несколько рекомендаций как сделать процесс внедрения менее болезненным. А пока, чтобы подсластить пилюлю поговорим о том что даст вам внедрение тестирования в легаси-системы.

Выгода от внедрения модульных тестов.

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

  • Фиксация требований
  • Защита от регресса
  • Документация
  • Отладка
  • Рефакторинг
  • Уменьшение стоимости поддержки
  • Увеличение качества кодовой базы и дизайна системы
  • Уменьшение времени на реализацию задач
    • Быстрая обратная связь об ошибках
    • Уменьшение времени их участия тестировщиков при реализации задачи
    • Сокращение количества итераций доработки задачи
  • Высвобождение тестировщиков от рутины регресса
  • Сокращение time to market

Рекомендации

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

Дальше нужно проработать план, регламенты и прочие организационные моменты.

  • Тестируем только дорабатываемый код.
  • Не стремимся к 100% покрытию. На первых этапах достаточно одного, двух кейсов на задачу.
  • Устаивайте встречи, обсуждения по процессу внедрения, собирайте обратную связь, не стесняйтесь пересматривать подходы.
  • Заранее решите, как будет обрабатывать ситуации, когда тесты находят ошибки. Иногда исправление ошибки может создать немалые проблемы.

План работ

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

  • В первую очередь стоит ознакомиться с основными рекомендациями по написанию модульных тестов

  • Для начала основная цель писать максимально простые и полезные тесты.

  • Выбираем новые с минимальными зависимостями объекты/методы.

  • пишем тесты там где они очевидно нужны, там где нет, мы не заставляем их себя писать

Пару месяцев поработать в таком ключе, только очевидные тесты, от души исходят которые. Главное не делать тесты там где они вредят:

Не начинайте тестировать класс, который знает про множество других классов и общается с ними напрямую Не пытайтесь тестировать поведение, типа сколько раз вызвался метод если клиент активный, тестируйте только результат, там где можно сравнить $a == $b Не пишите много ассертов в одном тесте Не бойтесь дублирования в тестах, дублирование ради выразительности теста - добро, а не зло. Тест нам помогает понять как рабтать с нашим классом. Тесты нужно учиться писать, не старайтесь протестировать весь ваш легаси сразу, начните писать сначала очевидные тесты.

Использованные материалы: