Чувство модульных испытаний без TDD

У нас есть новый (довольно большой) проект, который мы планировали разработать с использованием TDD.

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

Добавлено: Я думаю, что это не дубликат >>> это вопрос << - Я понимаю разницу между UT и TDD. Мой вопрос не о различиях , но о смысле написания тестов Unit без TDD.

28 голосов | спросил ex3v 8 PM00000040000005431 2014, 16:56:54

6 ответов


52

TDD используется главным образом (1) для обеспечения покрытия, (2) и для ведения ремонтопригодного, понятного, тестируемого дизайна. Если вы не используете TDD, вы не получите гарантированного покрытия кода. Но это никоим образом не означает, что вы должны отказаться от этой цели и blithely жить с 0% покрытия.

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

ответил Kilian Foth 8 PM00000050000004931 2014, 17:02:49
21

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

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

Была нужна одна конкретная структура данных, которая позволила бы мне отслеживать произвольное количество бит. Поскольку проект находится в Java, я выбрал Java BitSet и немного изменил его (мне нужна была возможность отслеживать ведущий 0 s, который по-разному не использует BitSet от Java .....). После охвата 93% охвата я начал писать некоторые тесты, которые на самом деле подчеркивали бы систему, которую я написал. Мне нужно было проверить некоторые аспекты функциональности, чтобы они были достаточно быстрыми для моих конечных требований. Неудивительно, что одна из функций, которые я переопределил из интерфейса BitSet, был абсурдно медленным при работе с большими битовыми наборами (сотни миллионов бит в Это дело). Другие переопределенные функции полагались на эту одну функцию, поэтому это была огромная горло бутылки.

То, что я закончил, касалось чертежной доски и выяснения способа манипулирования базовой структурой BitSet, которая это long[]. Я разработал алгоритм, спросил коллег для их ввода, а затем я начал писать код. Затем я выполнил модульные тесты. Некоторые из них сломались, а те, которые указали мне точно, где мне нужно было посмотреть в моем алгоритме, чтобы исправить это. После исправления всех ошибок из модульных тестов я смог сказать, что функция работает так, как должна. По крайней мере, я был уверен в том, что этот новый алгоритм работал так же, как и предыдущий алгоритм.

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

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

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

ответил Shaz 8 PM00000070000003331 2014, 19:27:33
7

Вы можете сломать код примерно на 4 категории:

  1. Простые и редкие изменения.
  2. Простые и часто меняющиеся.
  3. Сложные и редкие изменения.
  4. Сложные и часто меняющиеся.

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

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

ответил Karl Bielefeldt 9 AM00000020000005731 2014, 02:50:57
1

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

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

Вместо этого, если вы сначала напишите весь производственный код, когда вы пишете тесты для него, вы будете ожидать, что они пройдут с первого запуска. Это очень проблематично, потому что вы, возможно, создали тест, который покрывает 100% вашего производственного кода, не утверждая правильного поведения (возможно, даже не выполняет никаких утверждений! Я видел это событие ), поскольку вы не видите, что он не смог сначала проверить, не работает ли он по правильной причине. Таким образом, у вас могут быть ложные срабатывания. Ложные срабатывания в конечном итоге нарушат доверие к вашему тестовому набору, по сути, заставляя людей снова прибегать к ручному тестированию, поэтому у вас есть стоимость обоих процессов (написание тестов + ручные тесты).

Это означает, что должен найти другой способ проверить ваши тесты , например TDD. Поэтому вы прибегаете к отладке, комментированию частей производственного кода и т. Д., Чтобы иметь возможность доверять испытаниям. Проблема в том, что процесс «тестирования ваших тестов» намного медленнее. Добавляя это время к тому времени, когда вы будете проводить специальные тесты вручную (потому что у вас нет автоматических тестов во время кодирования производственного кода), по моему опыту, получается общий процесс, который намного медленнее, чем практика TDD «по книге» (Кент Бек - TDD по примеру). Кроме того, я готов сделать ставку здесь и сказать, что действительно «тестирование ваших тестов» после того, как они были написаны, принимает гораздо больше дисциплины , чем TDD.

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

ответил MichelHenrich 9 PM00000090000001031 2014, 21:08:10
0

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

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

ответил Tom W 9 PM00000010000000431 2014, 13:54:04
0

На самом деле дядя Боб упомянул очень интересный момент в одном из своих клипов «Чистые кодеры». Он сказал, что цикл Red-Green-Refactor можно применять двумя способами.

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

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

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

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

ответил Songo 9 PM00000070000002931 2014, 19:02:29

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132