Может ли модульное тестирование быть успешно добавлено в существующий производственный проект? Если да, то как и стоит?

Я настоятельно рекомендую добавить модульное тестирование к существующему проекту, который находится в процессе производства. Это было начато 18 месяцев назад, прежде чем я действительно смог увидеть какую-либо пользу TDD (лицевая ладонь), так что теперь это довольно большое решение с рядом проектов, и у меня нет туманной идеи, с чего начать в добавлении модульных тестов. Что заставляет меня считать, что изредка появляется старая ошибка, или ошибка исправлена ​​как исправленная, не будучи исправлена. Тестирование модулей уменьшит или предотвратит эти проблемы.

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

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

Итак, я думаю, что я тоже спрашиваю:

  • Стоит ли существующее решение, которое в производстве?
  • Было бы лучше проигнорировать тестирование для этого проекта и добавить его в возможно ли переиздание будущего?
  • Что будет более полезным; расходы несколько недель, добавляя тесты или несколько недели, добавляя функциональность?

(Очевидно, что ответ на третий вопрос полностью зависит от того, разговариваете ли вы с менеджером или разработчиком)


Причина баунти

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

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

Ответ 1

Я ввел модульные тесты для кодовых баз, которые ранее не были. В последнем крупном проекте, в котором я участвовал, где я это делал, продукт уже был в производстве с нулевыми модульными тестами, когда я приехал в команду. Когда я ушел - через 2 года - у нас было 4500+ или около того тестов, дающих около 33% кода в кодовой базе с 230 000 + производством LOC (приложение Win-Forms реального времени в реальном времени). Это может показаться низким, но результатом стало значительное улучшение качества кода и скорости дефектов - плюс улучшение морального духа и рентабельности.

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

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

Кроме того, и особенно для вашей ситуации, добавление модульных тестов к существующей базе кода, которая не имеет тестов, также является специализированным навыком. Если вы или кто-то из вашей команды не имеет успешного опыта внедрения модульных тестов в существующую базу кода, я бы сказал, что чтение Feather book является обязательным (не необязательно или настоятельно рекомендуется).

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

Теперь, для ваших комментариев и вопросов:

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

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

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

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

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

Хорошей новостью является то, что по прошествии месяцев (и даже лет) ваш код постепенно станет "правильным" хорошо учтенным и хорошо протестированным кодом.

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

Есть ли какой-либо процесс/шаги, которые должны соблюдаться, чтобы убедиться, что существующие решения были правильно протестированы, а не просто связаны?

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

Обучите своих людей.

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

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

Время сборки всегда должно быть FAST. Если время сборки медленное, ваши навыки тестирования устройства отстают. Найдите медленные тесты и улучшите их (отделите производственный код и тест в изоляции). Хорошо написано, вы должны легко иметь несколько тысяч модульных тестов и до сих пор завершить сборку менее чем за 10 минут (~ 1-мс/тест - это хорошая, но очень грубая рекомендация, некоторые исключения могут применяться как код с использованием отражения и т.д.).

Осмотреть и адаптировать.

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

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

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

Два грубых вторичных индикатора - это общее покрытие кода и скорость сборки.

Это стоит усилий для существующего решения, которое в производстве?

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

Было бы лучше проигнорировать тестирование для этого проекта и добавить его в возможную будущую переписывание?

Вы должны были бы учитывать не только инвестиции в людей и навыки, но, самое главное, общую стоимость владения и ожидаемый срок службы системы.

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

Что будет более полезным; потратив несколько недель на добавление тестов или несколько недель, добавив функциональность?

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

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

Кроме того, добавление единичных тестов к существующей кодовой базе любого значительного размера проекта - это БОЛЬШОЕ предприятие, которое требует приверженности и настойчивости. Вы не можете изменить что-то фундаментальное, ожидать много обучения на этом пути и попросить вашего спонсора не ожидать какой-либо ROI, остановив поток деловой ценности. Это не будет летать, и, честно говоря, это не должно быть.

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

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

Надеюсь, что поможет

Ответ 2

  • Это стоит усилий для существующего решения, которое в производстве?

Да!

  • Было бы лучше проигнорировать тестирование для этого проекта и добавить его в возможную будущую переписывание?

Нет!

  • Что будет более полезным; потратив несколько недель на добавление тестов или несколько недель, добавив функциональность?

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

  • Сколько времени вам потребуется, чтобы проверить весь этот код? Дни? Недели? Месяцы? Много лет?
  • Для кого вы пишете этот код? Платить клиентам? Профессор? Проект с открытым исходным кодом?
  • Каково ваше расписание? У вас есть жесткие сроки, с которыми вы должны встретиться? У вас есть какие-то крайние сроки?

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

  • Любой новый код, который вы пишете, должен быть полностью под unit test
  • Любой старый код, к которому вы прикасаетесь (исправление ошибок, расширение и т.д.), следует помещать под unit test

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

Edit:

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

Это похоже на вопрос: "Каковы плюсы и минусы использования источника управления?" или "Каковы плюсы и минусы опроса людей перед их наймом?" или "Каковы плюсы и минусы для дыхания?"

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

Ответ 5

Это абсолютно того стоит. Наше приложение имеет сложные правила перекрестной проверки, и нам недавно пришлось внести существенные изменения в бизнес-правила. Мы столкнулись с конфликтами, которые мешали пользователю экономить. Я понял, что на это потребуется время, чтобы разобраться в этом вопросе (требуется несколько минут, чтобы добраться до точки, где были проблемы). Я хотел ввести автоматические модульные тесты и установить фреймворк, но я не сделал ничего, кроме нескольких фиктивных тестов, чтобы убедиться, что все работает. С новыми бизнес-правилами я начал писать тесты. Тесты быстро определили условия, вызвавшие конфликты, и нам удалось выяснить правила.

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

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

Ответ 6

Я добавлю свой голос и скажу "да", это всегда полезно!

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

  • Black-box= тесты, которые написаны без специального знания о реализации, обычно выкрикивая в крайних случаях, чтобы убедиться, что все происходит, как ожидал наивный пользователь.
  • White-box= тесты, которые написаны со знанием реализации, которые часто пытаются использовать известные точки отказа.
  • Единичные тесты= тесты отдельных единиц (функции, разделяемые модули и т.д.). Например: убедитесь, что ваш класс массивов работает так, как ожидалось, и что ваша функция сравнения строк возвращает ожидаемые результаты для широкого диапазона входных данных.
  • Функциональные тесты= тесты всей системы все сразу. Эти тесты будут выполнять большой кусок системы сразу. Например: init, открыть соединение, сделать некоторые вещи в реальном мире, закрыть, завершить. Мне нравится проводить различие между этими и модульными тестами, потому что они служат другой цели.

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

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

Как и другие, я также напомню вам о двух самых важных вещах в TDD:

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

Ответ 7

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

Одна из первых вещей, которые мы сделали (после создания сервера непрерывной сборки), заключалась в добавлении тестов регрессии. Это были сквозные тесты.

  • Каждый набор тестов начинается с инициализации базы данных до известного состояния. На самом деле у нас есть десятки регрессионных наборов данных, которые мы сохраняем в Subversion (в отдельном хранилище из нашего кода из-за огромного размера). Каждый тест FixtureSetUp копирует один из этих наборов данных регрессии в временную базу данных, а затем запускается оттуда.
  • Настройка тестового устройства затем запускает некоторый процесс, результаты которого нас интересуют. (Этот шаг не является обязательным - некоторые регрессионные тесты существуют только для проверки отчетов.)
  • Затем каждый тест запускает отчет, выводит отчет в CSV файл и сравнивает содержимое этого CSV с сохраненным снимком. Эти снимки .csvs хранятся в Subversion рядом с каждым набором данных регрессии. Если вывод отчета не соответствует сохраненному снимку, тест не выполняется.

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

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

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

Регрессионные тесты имеют проблемы: они медленные, и есть слишком много причин, по которым они могут сломаться. Но, по крайней мере, для нас, они так стоили. За последние пять лет они поймали множество ошибок, и они поймают их в течение нескольких часов, а не ждут цикла QA. У нас все еще есть те оригинальные регрессионные тесты, которые распространяются по семи различным машинам непрерывной сборки (отдельно от тех, которые проводят быстрые модульные тесты), и мы даже время от времени добавляем к ним, потому что у нас есть так много кода, что наши 6000 + модульные тесты не распространяются.

Ответ 8

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

На этом этапе помните, что я говорю о выборочном добавлении модульных тестов, не пытаясь создать набор тестов, аналогичных тем, которые существовали бы, если бы вы практиковали TDD с самого начала. Поэтому в ответ на вторую половину вашего второго вопроса: укажите точку использования TDD в вашем следующем проекте, будь то новый проект или переписывание (извинения, но вот ссылка на другую книгу, которую вы действительно должны читать: Расширяющееся объектно-ориентированное программное обеспечение, ориентированное на тесты)

Мой ответ на третий вопрос совпадает с первым: это зависит от контекста вашего проекта.

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

Ответ 9

Вы не упомянули язык реализации, но если в Java вы можете попробовать этот подход:

  • В отдельном тестировании регрессии дерева дерева или "дымовых" тестах используется инструмент для их создания, который может приблизить вас к охвату на 80%. Эти тесты выполняют все логические пути кода и проверяют с этого момента, что код все еще делает то, что он делает в настоящее время (даже если присутствует ошибка). Это дает вам защитную сетку от непреднамеренно изменяющегося поведения при выполнении необходимого рефакторинга, чтобы сделать код легко проверяемым единицей вручную.

    • Предложение продукта. Раньше я использовал бесплатный веб-продукт Junit Factory, но, к сожалению, сейчас он закрыт. Однако продукт живет в коммерчески лицензированном генераторе JAnit AgitarOne по адресу http://www.agitar.com/solutions/products/automated_junit_generation.html
  • Для каждой ошибки, которую вы исправляете, или функции, которую вы добавляете с этого момента, используйте подход TDD для обеспечения того, чтобы новый код был предназначен для проверки и размещения этих тестов в обычном дереве исходных тестов.

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

  • При внесении изменений (исправлений ошибок или функций) через TDD, когда это завершено, вероятно, сбой компаньона smoke test. Убедитесь, что сбои ожидаются из-за внесенных изменений и удаляют менее читаемый smoke test, так как ваша написанная вручную unit test имеет полный охват этого улучшенного компонента. Следите за тем, чтобы ваше тестовое покрытие не уменьшалось, оставаясь неизменным или увеличиваясь.

  • При исправлении ошибок записывайте сбой unit test, который сначала выдает ошибку.

Ответ 10

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

Определите области проектов/модулей, в которых исправлены ошибки. начните с этих проектов, чтобы писать тесты. Совершенно разумно писать тесты для новых функций и исправления ошибок.

Это стоит усилий для существующего решение, которое в производстве?

Да. Вы увидите эффект от ошибок и упрощения обслуживания

Было бы лучше проигнорировать тестирование для этого проекта и добавить его в возможно ли переписать новую версию?

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

Что будет более полезным; расходы несколько недель, добавляя тесты или несколько недель с добавлением функциональности?

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

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

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

Ответ 14

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

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

Что будет более полезным; потратив несколько недель на добавление тестов или несколько недель, добавив функциональность?
Для новой функциональности (кода) это просто. Сначала вы пишете unit test, а затем - функциональность. Для старого кода вы решаете путь. Вам не нужно иметь все модульные тесты на месте... Добавьте те, которые больно вам больше не нужны... Время (и ошибки) расскажет, на какой из них вам нужно сосредоточиться;)

Ответ 15

Обновление

Через 6 лет после первоначального ответа у меня немного другое мнение.

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

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

Ранее ответ

Я собираюсь поднять несколько бровей здесь:)

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

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

Почему?

  • Единичные тесты проверяют только те тесты кода - независимо от того, использует ли код то, для чего он предназначен, - это не замена для ручного тестирования, которое в любом случае должно быть выполнено (чтобы выявить функциональные ошибки, проблемы удобства использования и все другие виды вопросы)

  • Серийные тесты требуют времени! Теперь, когда я родом, драгоценный товар - и бизнес обычно выбирают лучшую функциональность над полным набором тестов.

  • Если ваше приложение даже отдаленно полезно для пользователей, они собираются запросить изменения - так что у вас будут версии, которые будут делать что-то лучше, быстрее и, вероятно, делать что-то новое - также может быть много рефакторинга, поскольку ваш код растет. Поддержание полноценного набора unit test в динамической среде - головная боль.

  • Единичные тесты не повлияют на воспринимаемое качество вашего продукта - качество, которое видит пользователь. Конечно, ваши методы могут работать точно так же, как в первый день, интерфейс между уровнем представления и бизнес-слоем может быть нетронутым - но угадайте, что? Пользователю все равно! Получите настоящие тестеры для тестирования вашего приложения. И чаще всего эти методы и интерфейсы должны измениться в любом случае, рано или поздно.

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

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

Ответ 16

Невероятно, чтобы у вас когда-либо было значительное покрытие тестов, так что вы должны быть тактичны о том, где вы добавляете тесты:

  • Как вы уже упоминали, когда вы обнаружите ошибку, пришло время написать тест (воспроизвести его), а затем исправить ошибку. Если вы видите, что тест воспроизводит ошибку, вы можете быть уверены, что это хороший тест. Учитывая такую ​​большую часть ошибок, это регрессии (50%?), Почти всегда стоит писать регрессионные тесты.
  • Когда вы погружаетесь в область кода, чтобы изменить его, это хорошее время для написания тестов вокруг него. В зависимости от характера кода подходят различные тесты. Здесь есть один хороший совет .

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

Удачи!

Ответ 18

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

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

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

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

Ответ 19

Я не опытный эксперт TDD, но, конечно, я бы сказал, что это невероятно важно для unit test столько, сколько вы можете. Поскольку код уже на месте, я бы начал с получения какой-то автоматизации unit test. Я использую TeamCity для выполнения всех тестов в своих проектах, и это дает вам хорошее резюме того, как это сделали компоненты.

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

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

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

Оттуда я получаю ваш сервер сборки или любую имеющуюся у вас автоматизацию, настроенную с помощью инструмента покрытия кода. Они создают неприятные гистограммы с большими красными зонами, где у вас плохое покрытие. Теперь 100% охват не является вашей целью, и 100% -ый охват обязательно означает, что ваш код пуленепробиваемый, но красный бар определенно мотивирует меня, когда у меня есть свободное время.:)

Ответ 20

Есть так много хороших ответов, поэтому я не буду повторять их содержание. Я проверил ваш профиль и, похоже, вы разработчик С#.NET. Из-за этого я добавляю ссылку на Microsoft PEX и Moles, который может помочь вам с автогенерирующими модульными тестами для устаревшего кода. Я знаю, что автогенерация - это не лучший способ, но, по крайней мере, это способ начать. Проверьте эту интересную статью из журнала MSDN об использовании PEX для устаревшего кода.

Ответ 21

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

Ответ 22

Я предлагаю вам прочитать статью специалистом TopTal, в которой объясняется , где, чтобы начать добавлять тесты: она содержит много математики, но основная идея:

1) Измерьте свой код Afferent Coupling (CA) (насколько класс используется другими классами, что означает, что его разрыв может повредить)

2) Измерьте свой код Cyclomatic Complexity (CC) (более высокая сложность = более высокая степень нарушения)

Вам нужно определить классы с высоким CA и CC, то есть иметь функцию f (CA, CC), а классы с наименьшими различиями между двумя метриками должны получить наивысший приоритет для покрытия тестирования.

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

Ответ 23

Да. Нет. Добавление тестов.

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