Имеет ли смысл добавлять модульные тесты для хорошо известного устаревшего кода?

21
  • Я говорю о модульных тестах в смысле TDD. (Не автоматизированная «интеграция», или то, что вы любите называть тестами.)
  • Устаревший код как в: (C ++) код без тестов. (см .: « Эффективная работа Майкла Фезерса с устаревшим кодексом» )
  • Но также унаследованный код, такой как: Код, с которым наша команда работала последние 10-5 лет, поэтому мы очень часто имеем хорошее представление о том, где что-то изменить.
  • У нас есть модульные тесты (через Boost.Test) для некоторых модулей, которые пришли позже или были «естественными» для модульных тестов (общие контейнеры для конкретных приложений, строковые вещи, сетевые помощники и т. Д.)
  • У нас пока нет надлежащих автоматических приемочных испытаний.

Недавно у меня было «удовольствие» реализовать 3 новые функции, ориентированные на пользователя.

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

Теперь я действительно добавил немного кода. (Я думаю, один метод и несколько линий вызова для каждой функции.)

Извлечение этого кода (с помощью любого из методов, предложенных в WEwLC ), чтобы модульный тест имел смысл (а не полную тавтологию), легко занял бы еще 2-4 часа, если не больше. Это добавило бы 50% -100% времени к каждой функции, без немедленной выгоды, так как

  1. Мне не нужен юнит-тест, чтобы понять что-нибудь о коде
  2. Ручное тестирование - это тот же объем работы, который мне все еще нужно проверить, правильно ли код интегрирован в остальную часть приложения.

Конечно, если позже «кто-то» придет и коснется этого кода, он теоретически может получить некоторую пользу от этого модульного теста. (Только теоретически, поскольку этот проверенный островок кода будет жить в океане непроверенного кода.)

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

Это что-то типичное для сильно связанного унаследованного кода? Я ленивый / мы устанавливаем неправильные приоритеты как команда? Или я осторожен, только проверяю вещи, где накладные расходы не слишком высоки?

Мартин Ба
источник
что если какой-то другой отдел возьмет на себя ваш "хорошо известный устаревший код"? Что ребята там будут делать с этим?
Алекс Феодоридис

Ответы:

18

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

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

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

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

прецизионный самописец
источник
Что такое хороший кусок кода? Тот, который хорошо спроектирован, протестирован, задокументирован и пригоден для будущего, или тот, за который вам платят? Как всегда: у тебя это может быть хорошо ; Вы можете иметь это дешево ; Вы можете иметь это быстро . Выберите любые два, третий - ваши расходы.
Сардатрион - Восстановить Монику
2
«Я бы всегда спорил о новом коде» ... «новый код» в устаревшей кодовой базе или «новый новый код»? :-)
Мартин Ба
ПДР имеет правильную идею. Это инженерное решение (одно с компромиссами). Как правило, если у вас есть большой кусок проверенного кода, рекомендуется оставить его в покое. Я видел, как TDD работает над унаследованным кодом (всего год, но этого достаточно), что в итоге стоило нескольких месяцев и в итоге тратит деньги и ломает унаследованное приложение в течение нескольких месяцев, пока ошибки, внесенные в рефактор TDD, не будут исправлены. Если код / ​​функция созданы и протестированы, не ломайте их, чтобы добавить инструментарий (TDD), чтобы сказать вам кое-что, что вы уже знали (что он работает).
Anon
10

Преимущество модульных тестов в смысле TDD состоит в том, чтобы получить что-то, что стоит само по себе, без необходимости устной традиции, построенной за годы стабильной командой.

Это большая удача, что одна и та же команда была в одном проекте в течение стольких раз. Но это в конечном итоге изменится. Люди болеют, скучают или повышаются. Они двигаются, уходят на пенсию или умирают. Новые приходят с новыми идеями и стремлением реорганизовать все так, как они учились в школе. Компании продаются и покупаются. Политики управления меняются.

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

mouviciel
источник
3

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

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

Сардатрион - Восстановить Монику
источник
1
Но но НО! :-) Это немного должно означать увеличение времени на 100%, необходимое для реализации новой функции. Это не уменьшает время, необходимое для реализации последующих функций. Это может уменьшить время, необходимое для смены вещей.
Мартин Ба,
3
Вы удостоверяетесь, что изменения в этой области кода не привносят новых ошибок, что новые (менее опытные пользователи) могут получить четкое представление о коде, и что побочные эффекты, влияющие на эту область, кашляют во время тестирования, а не при выпуске время. Тестирование помогает проверить, что код делает то, что должен, что не облегчает добавление функций позже. Я считаю, что добавление тестов, даже в устаревшем коде, полезно в среднесрочной и долгосрочной перспективе . Если ваша компания не заботится о среднесрочном и долгосрочном плане, я бы искал другую компанию.
Сардатрион - Восстановить Монику
1
@ Мартин, потому что ясно, что вы делаете, кодируйте то, что, по вашему мнению, должно быть у этой функции, а затем отправляете ее. На любом этапе тестирование вообще не проводится ... нет, подожди. Как разработчики, мы все тестируем наш код (по крайней мере, вручную), прежде чем сказать, что это сделано. Замена «от руки» на «написание автоматизированного теста» не приводит к увеличению времени на 100%. Часто я нахожу это примерно в то же время.
Каз Драгон
1
@Kaz - «Замена» вручную »на« написание автоматизированного теста »не на 100% увеличивает время. Часто я нахожу, что это примерно в то же время». - YMMV, но для моей кодовой базы это явно неправильно (как изложено в вопросе).
Мартин Ба,
3
@Kaz: То, что я имел в виду :-), было: модульный тест проверяет мой код изолированно Если я не пишу модульный тест, я не тестирую код изолированно, а только в том случае, если код вызывается правильно и дает желаемый результат в приложении. Эти два пункта (которые называются «правильно» и «приложение делает то, что нужно») я все равно должен проверить (вручную), и они не охватываются модульным тестом. И модульный тест не охватил бы эти две точки, но "просто" проверил бы мою функцию изолированно. (И это юнит-тестирование было бы дополнительным и, насколько я могу судить, ничем не компенсировало его.)
Мартин Ба,
2

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

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

Суть в том, что если ваша система редко изменяется, то, возможно, не стоит писать модульные тесты, но если она подвергается регулярным изменениям, то это того стоит.

Том Сквайрс
источник
1

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

Да, для написания модульных тестов может потребоваться еще 2-3 часа, но если код будет возвращен из тестирования, вам придется снова все вручную проверить и снова задокументировать свое тестирование - вы делаете это, не так ли? Иначе как кто-нибудь узнает, что вы тестировали и какие значения использовали?

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

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

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

mcottle
источник
"и снова задокументируй свое тестирование - не так ли?" - {надевает циничную шляпу:} Конечно, нет. Мы не в сказочной стране разработчиков. Материал внедряется, тестируется и поставляется. Позже это сломано и исправлено и проверено и отправлено.
Мартин Ба,
Я надеюсь, что все проверяется вручную независимо от количества юнит-тестов. Автоматические приемочные испытания - это совсем другое дело. Но тогда приемочные тесты не усложняются тем, что кодовая база является унаследованной, поэтому здесь она выходит за рамки.
фунтовые
2
Маккоттл - Вам не хватает жизненно важной точки. Модульное тестирование не уменьшит время, необходимое для «ручного тестирования функциональности» готовой функции. Мне все еще нужно просмотреть все диалоговые окна, связанные с разумным подмножеством возможных входных данных, чтобы убедиться, что фактическое законченное приложение в собранном виде выполняет то, что должно делать. (Я допускаю, что теоретически модульное тестирование может помочь ограничить этот цикл ручного тестирования только одним циклом, если модульные тесты убедятся, что я не обнаружу никаких очевидных проблем только во время ручного тестирования.)
Martin Ba
0

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

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

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

Марьян Венема
источник
1
«Без модульных тестов у вас нет других средств, чтобы гарантировать, что ваша функция не была непреднамеренно нарушена, даже если сама эта функция не была изменена». - Модульные тесты не помогут. Чтобы быть уверенным , мне понадобятся автоматические интеграционные / приемочные тесты.
Мартин Ба,
Да, юнит-тесты - это только первый шаг. Отредактированный ответ, чтобы уточнить
Marjan Venema