Является ли хорошей идеей написать все возможные тестовые примеры после преобразования команды в TDD для достижения полного охвата?

17

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

Теперь, когда все сроки прошли и все спокойно, все согласились превратить нас в продуктивную команду, основанную на TDD / BDD ... Да!

Теперь вопрос о коде, который у нас уже есть: (1) все еще хорошо или хорошая идея прекратить большую часть разработки и начать писать все возможные тестовые сценарии с самого начала, даже если все работает полностью ОКАЙ (пока!) ? Или (2) лучше подождать, пока что-то случится плохо, а затем во время исправления написать новые модульные тесты, или (3) даже забыть о предыдущих кодах и просто написать модульные тесты только для новых кодов и отложить все до следующего основного рефакторинга.

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

Примечание . Этот вопрос объясняет / представляет совершенно неловкую ситуацию в команде разработчиков. Это не обо мне или о моих коллегах; это просто воображаемая ситуация. Вы можете подумать, что это никогда не должно произойти, или менеджер по разработке несет ответственность за такой беспорядок! Но в любом случае, что сделано, то сделано. Если возможно, пожалуйста, не понижайте голос только потому, что считаете, что этого никогда не произойдет.

Мишель Гокан
источник
6
Вероятно, вам следует готовиться к следующему сроку, и вам больше не разрешено делать TDD. Возможно, рассказав кому бы то ни было, кто участвовал в последнем раунде технического долга, почему это не было хорошей идеей.
Джоншарп
1
@gnat Я думаю, это не повторяющийся вопрос. У упомянутой команды нет каких-либо тестов (даже интеграционных тестов)
Мишель Гокан
1
@gnat вопросы: что будет с нашими новыми юнит-тестами? Они могут показаться неполными или даже бесполезными без написания всех модульных тестов для ранее написанных кодов. Вопрос, который вы упоминаете, не охватывает эту конкретную проблему.
Мишель Гокан
1
Невозможно написать все возможные тестовые случаи. Это только полезно , чтобы написать все тест- случаи вы заботитесь о. Например, если вам нужна функция, которая будет принимать intзначение и возвращать что-то конкретное, невозможно написать модульный тест для каждого возможного intзначения, но, вероятно, имеет смысл протестировать несколько полезных значений, которые могут привести к срабатыванию код, такой как отрицательные числа (включая minint), ноль maxintи т. д., чтобы убедиться, что некоторые граничные случаи покрыты.
Кристофер Шульц

Ответы:

36

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

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

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

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

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

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

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

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

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

Это хорошая идея написать все возможные тестовые случаи после преобразования команды в TDD?

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

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

(1) Это все еще нормально или хорошая идея - прекратить большую часть разработки и начать писать все возможные тестовые сценарии с самого начала, даже если все работает нормально (пока!)? Или

Нет. Это мышление "давайте сделаем полное переписывание". Это разрушает с трудом завоеванные знания. Не спрашивайте у руководства время написать тесты. Просто напишите тесты. Как только вы узнаете, что делаете, тесты не замедлят вас.

(2) лучше подождать, пока что-то плохое случится, а затем во время исправления написать новые модульные тесты, или

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

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

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

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

candied_orange
источник
37
«Тесты ускоряют ваше развитие, даже если никто не запускает их». - Я считаю, что это явно ложно. Это не то место, где можно начинать обсуждение этого вопроса, но читатели должны помнить, что точка зрения, представленная здесь, не единодушна.
Мартин Ба,
4
На самом деле часто тесты увеличивают вашу разработку в долгосрочной перспективе и для того, чтобы TDD был действительно эффективным, все должны в это верить, иначе вы бы потратили половину своей команды на исправление тестов, нарушенных другими.
hspandher
13
«Вы думаете, что TDD замедлит вас и заставит вас пропустить крайний срок». Я думаю , что , вероятно , это так. Никто не использует TDD, потому что они ожидают, что его первый срок будет выполнен быстрее. Реальная выгода (по крайней мере, по моим оценкам) - это текущие дивиденды, которые проверяют игру в будущем, выявляют регрессии и укрепляют уверенность в безопасных экспериментах. Я думаю, что это преимущество перевешивает первоначальные затраты на написание тестов, большинство, вероятно, с этим согласится, но если вам придется уложиться в сжатые сроки, у вас на самом деле нет выбора.
Александр - Восстановить Монику
1
Я нахожу это аналогом покупки дома. Если бы у вас была единовременная выплата за жилье, вы бы много сэкономили на процентах, и это было бы здорово в долгосрочной перспективе. Но если вам нужен дом сразу ... тогда вы вынуждены использовать краткосрочный подход, который является долгосрочным субоптимальным
Александр - восстановите Монику
3
TDD = может = повысить производительность, если тесты и код разрабатываются параллельно, а функциональность свежа для разработчика. Обзоры кода скажут вам, если другой человек считает код правильным. Тестовые случаи сообщат вам, реализуется ли спецификация, воплощенная в тестовом примере. В противном случае, да, TDD может быть затруднительным, особенно если нет функциональной спецификации, и автор тестов также занимается реверс-инжинирингом.
Джули в Остине
22

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

Учитывая устаревший код 1 , напишите модульные тесты в следующих ситуациях:

  • при исправлении ошибок
  • при рефакторинге
  • при добавлении новой функциональности в существующий код

Как бы ни были полезны юнит-тесты, создание полного комплекта юнит-тестов для существующей 1 кодовой базы, вероятно, не является реалистичной идеей. Силы, которые были, подтолкнули вас поставить в сжатые сроки. Они не позволяли вам создавать адекватные модульные тесты во время разработки. Как вы думаете, они дадут вам достаточно времени для создания тестов для «программы, которая работает»?

1 Устаревший код - это код без юнит-тестов. Это определение устаревшего кода TDD. Это применимо, даже если старый код доставлен недавно [даже если чернила еще не высохли].

Ник Алексеев
источник
Но тогда наши новые модульные тесты для новых функций могут показаться неполными или даже бесполезными без пропуска модульных тестов. Не так ли?
Мишель Гокан
7
(1) Бесполезно? Конечно, нет. По крайней мере, они тестируют новую функцию. В следующий раз, когда кто-то захочет изменить эту функцию, он будет использовать большую часть существующих тестов. (2) неполный? Может быть, а может и нет. Если вы также создадите модульные тесты, которые тестируют устаревшую функциональность, от которой зависит новая функция, тогда тесты могут быть достаточно полными для практических целей. Другими словами, создайте дополнительные модульные тесты, которые проникают в устаревшие функциональные возможности. На какую глубину проникнуть? Это зависит от архитектуры программы, доступных ресурсов, институциональной поддержки.
Ник Алексеев
Недостаток «писать тесты, когда вы наталкиваетесь на их необходимость», заключается в том, что существует повышенный риск того, что в результате вы получите множество тестов, написанных разными разработчиками с разными идеями. Я не говорю, что этот ответ неправильный, но он требует твердой руки, которая сохраняет качество и стиль тестов единообразными.
Флейтер
4
Однородность @Flater предлагает ложное утешение. Я хочу тесты, которые делают производственный код легко читаемым. Не тесты, которые все выглядят одинаково. Я прощу смешивание совершенно разных сред тестирования, если это облегчит понимание того, что делает производственный код.
candied_orange
2
@Flater Я не утверждал, что уродливый производственный код. Я утверждаю, что цель тестов - сделать рабочий код читабельным. Я с удовольствием приму эклектичную толпу тестов, которые облегчают чтение производственного кода. Будьте осторожны, чтобы единообразие стало самоцелью. Читаемость является королем.
candied_orange
12

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

  • более 30% покрытия (или пара интеграционных тестов): если ваши тесты не пройдены, что-то сильно испортилось (или ваши тесты ненадежны). К счастью, тесты предупредили вас быстро! Но релизы по-прежнему требуют обширного ручного тестирования.
  • покрытие более 90% (или большинство компонентов имеют поверхностные модульные тесты): если ваши тесты пройдены, программное обеспечение, скорее всего, в основном нормально. Непроверенные части являются крайними случаями, что хорошо для некритического программного обеспечения. Но релизы по-прежнему требуют ручного тестирования.
  • очень высокий охват функций / утверждений / веток / требований: вы воплощаете мечту TDD / BDD , и ваши тесты являются точным отражением функциональности вашего программного обеспечения. Вы можете выполнить рефакторинг с высокой степенью достоверности, включая масштабные архитектурные изменения. Если тесты пройдены, ваше программное обеспечение почти готово к выпуску; требуется только ручное тестирование дыма.

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

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

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

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

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

Амон
источник
«более 90% покрытия (или большинство компонентов имеют поверхностные модульные тесты): если ваши тесты пройдены, программное обеспечение, скорее всего, в основном нормально. Непроверенные части - это крайние случаи, что хорошо для некритического программного обеспечения ». Это звучит немного странно для меня, FWIW, я бы предпочел иметь 30% покрытия, состоящего в основном из крайних случаев, чем 90% покрытия, состоящего полностью из ожидаемого поведения пути (что легко сделать ручным тестировщикам); Я рекомендую думать "нестандартно" при написании тестов и основывать их на (необычных) тестовых случаях, обнаруженных вручную, когда это возможно.
августа
5

Не пишите тесты для существующего кода. Это того не стоит.

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

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

Кроме того, причина для TDD состоит в том, чтобы вы подумали о том, каковы точные требования к коду перед его написанием. Другим способом, вы уже сделали это.

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

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

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

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

RemcoGerlich
источник
1
Я категорически не согласен с «Не пишите тесты для существующего кода. Это того не стоит». Если код работает нормально, тесты могут быть единственной существующей спецификацией. И если код находится в ведении, добавление тестов - единственный способ гарантировать, что те функции, которые работают, не нарушаются, казалось бы, не связанными изменениями.
Джули в Остине
3
@JulieinAustin: С другой стороны, без спецификации вы точно не знаете, что должен делать код. И если вы еще не знаете, что должен делать код, вы можете написать бесполезные тесты - или, что еще хуже, вводящие в заблуждение тесты, которые слегка изменяют спецификацию - и теперь требуется случайное и / или неправильное поведение.
Чао
2

Тест - это средство передачи понимания.

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

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

Поэтому пишите только тесты для кода, с которым вы работаете.

Когда вы будете работать с кодом, вы будете учиться.

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

Промыть и повторить.

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

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

Два варианта:

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

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

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

  1. Подтвердите, что тесты пройдены успешно
  2. Сделать вам изменения
  3. Подтвердите, что тесты все еще успешны

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

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

хотя все работает полностью нормально (пока!)?

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

(3) даже забыть о предыдущих кодах и просто написать модульные тесты только для новых кодов и отложить все до следующего крупного рефакторинга

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

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

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

и отложить все до следующего крупного рефакторинга

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

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

Flater
источник
0

Мои два цента:

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

В качестве альтернативы, скажем, вы магазин SCRUM, ваша рабочая нагрузка представлена ​​емкостью, и вы можете выделить% от этого для модульного тестирования, но ...

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

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

RandomUs1r
источник