Нормально ли тратить столько, если не больше, на время написания тестов, чем на фактический код?

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

Это нормально или я делаю что-то неправильно?

Вопросы œ Является ли модульное тестирование или тестирование- ориентированное развитие стоит , а именно: Мы тратим больше времени на выполнение функционального теста, чем на внедрение самой системы, это нормально? - и ответы на них больше касаются того, стоит ли тестирование (как в случае« если мы пропустим писать тесты вообще? »). Хотя я убежден, что тесты важны, мне интересно, не тратит ли больше времени на тесты, чем на фактический код, или если это только я.

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

197 голосов | спросил springloaded 14 +03002015-10-14T01:27:18+03:00312015bEurope/MoscowWed, 14 Oct 2015 01:27:18 +0300 2015, 01:27:18

9 ответов


196

Я помню из курса по разработке программного обеспечения, который тратит ~ 10% времени разработки на новый код, а остальные 90% - отладка, тестирование и документация.

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

Наконец, тесты должны также удвоиться как документация! Нужно писать модульные тесты таким образом, чтобы код использовался для использования; то есть тесты (и использование) должны быть простыми, помещать сложный материал в реализацию.

Если ваши тесты сложны, тогда код, который они тестируют, вероятно, трудно использовать!

ответил esoterik 14 +03002015-10-14T02:16:48+03:00312015bEurope/MoscowWed, 14 Oct 2015 02:16:48 +0300 2015, 02:16:48
94

Это.

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

Рассмотрим простой код:

 public void SayHello (string personName)
{
    if (personName == null) throw new NullArgumentException ("personName");

    Console.WriteLine («Hello, {0}!», PersonName);
}

Какими будут тесты? Здесь можно протестировать как минимум четыре простых случая:

  1. Имя человека null. Исключено ли действительно? Это, по крайней мере, три строки тестового кода для записи.

  2. Имя человека "Jeff". Получаем ли мы «Hello, Jeff!» в ответ? Это четыре строки тестового кода.

  3. Имя человека - пустая строка. Какой результат мы ожидаем? Каков фактический результат? Боковой вопрос: соответствует ли он функциональным требованиям? Это означает еще четыре строки кода для модульного теста.

  4. Имя пользователя достаточно короткое для строки, но слишком долго, чтобы сочетаться с «Hello», и восклицательным знаком. Что происходит? ¹¹

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

Если отношение очень велико, в этом случае вы можете проверить несколько вещей:

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

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

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

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

Заметка о TDD

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


¹ Пусть n будет максимальная длина строки . Мы можем вызвать SayHello и передать по ссылке строку длиной n - 1, которая должна работать нормально. Теперь, на шаге Console.WriteLine, форматирование должно заканчиваться строкой длиной n + 8, что приведет к исключению. Возможно, из-за ограничений памяти даже строка, содержащая символы n /2, приведет к исключению. Вопрос, который следует задать, заключается в том, является ли этот четвертый тест единичным тестом (он похож на один, но может иметь гораздо более высокий эффект с точки зрения ресурсов по сравнению со средними модульными тестами), и если он проверяет фактический код или базовую структуру.

ответил Arseni Mourzenko 14 +03002015-10-14T01:49:36+03:00312015bEurope/MoscowWed, 14 Oct 2015 01:49:36 +0300 2015, 01:49:36
58

Я думаю, что важно различать два типа тестовых стратегий: модульное тестирование и интеграционное /приемочное тестирование.

Хотя в некоторых случаях требуется единичное тестирование, оно часто безнадежно перегружено. Это усугубляется бессмысленными метриками, навязанными разработчикам, например, «100% охват». http://www.rbcs-us.com/documents/Why- Most-Unit-Testing-is-Waste.pdf дает убедительный аргумент в пользу этого. При агрессивном модульном тестировании рассмотрите следующие проблемы:

  • Обилие бессмысленных тестов, которые не документируют бизнес-ценность, а просто существуют, чтобы приблизиться к 100% -ному охвату. Там, где я работаю, мы должны написать модульные тесты для фабрик , которые ничего не делают, кроме создания новых экземпляров классов. Это не добавляет никакой ценности. Или те длинные методы .equals (), сгенерированные Eclipse, - нет необходимости их проверять.
  • Чтобы упростить тестирование, разработчики разделили бы сложные алгоритмы на более мелкие тестируемые единицы. Звучит как победа, не так ли? Нет, если вам нужно открыть 12 классов, чтобы следовать за общим кодом. В этих случаях модульное тестирование может фактически уменьшить читаемость кода. Еще одна проблема заключается в том, что если вы нарезаете свой код на слишком мелкие кусочки, вы получите массу классов (или фрагментов кода), которые, как представляется, не имеют никакого обоснования, кроме того, что они являются подмножеством другого фрагмента кода.
  • Рефакторинг очень покрытого кода может быть затруднен, так как вам также необходимо поддерживать множество модульных тестов, которые зависят от него, работая именно так . Это усугубляется поведенческими модульными тестами, где часть вашего теста также проверяет взаимодействие соавторов класса (обычно издевается).

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

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

ответил firtydank 14 +03002015-10-14T10:58:49+03:00312015bEurope/MoscowWed, 14 Oct 2015 10:58:49 +0300 2015, 10:58:49
10

Не может быть обобщен.

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

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

ответил phresnel 14 +03002015-10-14T11:38:25+03:00312015bEurope/MoscowWed, 14 Oct 2015 11:38:25 +0300 2015, 11:38:25
3

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

Это означает, что:

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

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

Да, если вы говорите о написании тестов после факта, тогда вы будете проводить больше времени:

  • Определение желаемого поведения.
  • Определение способов тестирования желаемого поведения.
  • Выполнение зависимостей кодов для записи тестов.
  • Исправление кода для тестов, которые не выполняются.

Чем вы будете на самом деле писать код.

Итак, это ожидаемая мера.

ответил Laurent LA RIZZA 14 +03002015-10-14T11:37:43+03:00312015bEurope/MoscowWed, 14 Oct 2015 11:37:43 +0300 2015, 11:37:43
3

Я считаю, что это самая важная часть.

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

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

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

ответил Jesse 14 +03002015-10-14T07:16:28+03:00312015bEurope/MoscowWed, 14 Oct 2015 07:16:28 +0300 2015, 07:16:28
2

Это может быть для многих людей, но это зависит.

Если вы сначала пишете тесты (TDD), вы можете столкнуться с некоторым перекрытием за время, потраченное на запись теста, что действительно полезно для написания кода. Рассмотрим:

  • Определение результатов и ввода (параметров)
  • Соглашения об именах
  • Структура - куда поместить вещи.
  • Обычное старое мышление

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

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

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

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

ответил JeffO 14 +03002015-10-14T02:13:35+03:00312015bEurope/MoscowWed, 14 Oct 2015 02:13:35 +0300 2015, 02:13:35
2
  

Является ли обычным тратить столько, если не больше, на время написания тестов, чем на фактический код?

Да, это так. С некоторыми оговорками.

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

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

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

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

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

ответил Mike Nakis 6 SunEurope/Moscow2015-12-06T19:47:41+03:00Europe/Moscow12bEurope/MoscowSun, 06 Dec 2015 19:47:41 +0300 2015, 19:47:41
0
  

Нормально ли тратить столько, если не больше,   чем фактический код?

  • Да для написания unit-tests (протестируйте модуль отдельно ), если код с высокой связью (устаревший, недостаточно разделение проблем , отсутствует инъекция зависимостей , а не tdd developed )
  • Да для записи интеграции /приемочных испытаний , если логика быть проверен только с помощью gui-code
  • Нет для записи интеграционных /приемных тестов до тех пор, пока GUI-код и бизнес-логика разделены (Тест не требует взаимодействия с gui)
  • Нет для написания модульных тестов, если есть разделение проблем, инъекция зависимостей, код testdriven developed (tdd)
ответил k3b 14 +03002015-10-14T11:36:12+03:00312015bEurope/MoscowWed, 14 Oct 2015 11:36:12 +0300 2015, 11:36:12

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

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

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