Подтвердить что ты не робот

Есть ли такая вещь, как чрезмерное модульное тестирование?

Я не новичок в концепции модульного тестирования, но в то же время я еще не освоил их.

Один вопрос, который недавно проходил через мою голову, когда я писал модульные тесты при написании своего кода с использованием методологии TDD: на каком уровне я должен тестироваться?

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

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

Мне может потребоваться разъяснить этот вопрос, прежде чем люди предполагают, что я против использования TDD...

То, с чем я борюсь, - это гранулярность моего теста....

  • Когда у моего приложения есть файл конфигурации, я проверить, что значения могут быть получены из файла? Я наклоняюсь к да.... но....
  • Затем я пишу unit test для каждой возможной конфигурации ценность, которая будет присутствовать? т.е. проверить, что они существуют... и могут быть проанализированы на правильный тип...
  • Когда мой приложение записывает ошибки в журнал чтобы проверить, что он способен писать журнал? Должен ли я тогда писать тесты для проверки того, что записи фактически сделано в журнал?

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

4b9b3361

Ответ 1

[Обновить:] Нашел краткий ответ на этот вопрос в TDD ByExample - Pg194.

Простой ответ, поставленный Phlip "Писать тесты, пока не возникнет страх превратился в скуку".

[/ Обновить]

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

Итак, чтобы ответить на ваш вопрос.. некоторые рекомендации.

  • Если вы следуете за TDD, у вас никогда не будет кода, который не покрывается unit test.., поскольку вы только пишете (минимальный) код, чтобы передать сбой unit test и не более, Следствие. Каждая проблема должна завершиться неудачей unit test, которая указывает местоположение дефекта. Тот же дефект не должен приводить к разрыву десятков UT.
  • Не проверяйте код, который вы не пишете. Следствие: вы не проверяете код фреймворка (например, чтение значений из файла app.config). Вы просто считаете, что это работает. И сколько раз вы нарушали рамочный код? Рядом с нолем.
  • Если есть сомнения, рассмотрите вероятность сбоя и взвесить его на расходы, связанные с написанием автоматизированного тестового примера. Написание тестовых примеров для аксессуаров/повторное тестирование набора данных.
  • Устранить боль. если вы обнаружите, что периодически возникают проблемы в определенной области, заходите в тестовую проводку. Вместо того, чтобы тратить время на чтение избыточных тестов для областей, которые, как вы знаете, довольно прочные. например Третья сторона/команда библиотеки продолжает ломаться в интерфейсе.. не работает, как предполагается. Маки не поймают его. У вас есть набор типа регрессии с использованием настоящего соавтора и выполнение некоторых тестов на здравомыслие, чтобы проверить ссылку, если вы знаете, что это проблема ребенка.

Ответ 2

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

  • тестирование получателей и сеттеров.
  • тестирование работы базового языка.

Ответ 3

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

Ответ 4

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

Каждая зарегистрированная ошибка должна приводить к по меньшей мере одному unit test.

Относительно некоторых ваших особенностей: я бы определенно проверил мой синтаксический анализатор конфигурационных файлов, чтобы увидеть, что он может анализировать каждое значение каждого ожидаемого типа. (Я обычно полагаюсь на Lua для файлов конфигурации и разбора, но это все равно оставляет мне какое-то тестирование.) Но я бы 't написать unit test для каждой записи в файле конфигурации; вместо этого я бы написал табличную платформу тестирования, которая описала бы каждую возможную запись и сгенерировала бы тесты из этого. Я бы, вероятно, создал документацию из того же описания. Я мог бы даже генерировать парсер.

Когда ваше приложение записывает записи в журнал, вы переключаетесь на интеграционные тесты. Лучшим подходом было бы иметь отдельный компонент регистрации, такой как syslog. Затем вы можете unit test регистратор, поместить его на полку и повторно использовать. Или даже лучше, повторно использовать syslog. После короткого теста интеграции вы можете узнать, правильно ли работает ваше приложение с syslog.

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

Я надеюсь, что это поможет.

Ответ 5

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

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

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

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

Ответ 6

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

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

Ответ 7

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

помните, что для тестирования функций требуется ; все остальное следует из этого

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

EDIT: Кажется, есть какая-то путаница в отношении того, что я пытаюсь сказать. Я не говорю, что модульное тестирование и тестирование функций - одно и то же - они нет. Per wikipedia: "единица - наименьшая проверяемая часть приложения", и логически такие "единицы" меньше, чем большинство "функций",.

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

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

Ответ 8

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

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

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

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

Ответ 9

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

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

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

Конечно, можно продумать то же самое, что можно переоценить.

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

О тривиальных тестах, eXtreme Programming говорит об этом: " проверить все, что может сломаться".

Ответ 13

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

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

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

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

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

Ответ 14

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

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

Ответ 15

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

Ответ 16

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

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

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

Ответ 17

Я думаю, это правило также должно применяться к TDD для предотвращения чрезмерного unit test.

Ответ 18

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

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

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