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

В чем смысл модульного тестирования?

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

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

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

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

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

EDIT: Спасибо за ответы, я думаю, что сейчас понимаю. Я вижу, что несколько человек проголосовали за удаление, но я хотел бы поблагодарить людей, которые ответили; это действительно помогло!

4b9b3361

Ответ 1

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

  • Повысить уверенность в правильности кода, который вы пишете.
  • повысить доверие к правильности рефакторов
  • сделать отслеживание, где ошибка была введена на этапе тестирования намного проще

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


Рассмотрим следующее...

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

     A      C      E
    / \    / \    / \
in-<   >--<   >--<   >-out
    \ /    \ /    \ /
     B      D      F

Вы можете проверить это, вручную вставляя входы и проверяя выходы - сначала вы ввели некоторые входы, которые активировали A, C, E; то вы добавили бы некоторые из них, которые делали A, C, F и т.д., пока вы не накрыли все через B, D, F.

Но имейте в виду, что каждый из B, D и F имеет свои собственные параметры и потоки, которые необходимо протестировать, - мы скажем, что, возможно, 10 вариантов для каждого. Так что по крайней мере 10*10*10 = 1000 разные входы, которые нужно проверить, только для случая A, C, E. Существует 8 различных возможных потоков через эти 6 компонентов, так что 8000 различные комбинации входов, которые вам нужно проверить, чтобы убедиться, что вы нажмете все различные возможные входы.

С другой стороны, вы могли бы unit test. Если вы четко определяете границы устройства для каждого компонента, вы можете написать 10 модульных тестов для A, 10 для B и т.д., Проверяя эти границы. Это дает вам в общей сложности 60 единичных тестов для компонентов, плюс несколько тестов (например, 5 на поток, так 40), которые гарантируют, что все компоненты связаны правильно. Это всего 100 тестов, которые эффективно выполняют те же функции.

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

Ответ 2

Короткий ответ: да, ты высокомерен. ;)

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

Теперь.... Откуда вы знаете, что ваш код совершенен и корректен? Вы должны проверить это. Если это не было проверено, вы не можете поверить, что это работает.

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

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

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

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

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

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

Нет, совсем нет.

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Хотя у меня такое чувство, что он просто сказал, что, поскольку он знал, что мне не нравится комментировать код, но предпочитаю самодокументированный исходный код, все еще есть интересная точка зрения;)

В качестве дополнительной заметки вы также должны взглянуть на coverage, когда вы выполняете модульные тесты или разрабатываете тестовые комплекты, которые вы хотите охватить как можно ближе к 100%, что означает, что тесты протестировали 100% вашего кода, включая все различные пути, которые могут потребоваться, это довольно сложно и может сделать ваш тестовый код в несколько раз большим, чем ваш источник, хотя вы может также автоматизировать ваш тестовый код, простым примером будет тестирование базы данных sql, вы можете создать программу, которая генерирует все возможные SQL-команды и проверяет, что они правильно выполнены, я думаю, что sqlite3 имеет более 91 миллиона строк теста, http://www.sqlite.org/testing.html очень интересно... о, это что-то he также защищает.

Ответ 5

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

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

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

Регрессионное тестирование - это ваша единственная защита от такого рода вещей.

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

Если у вас есть тесты по существующим функциям, облегчит ли расширение функциональность?

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

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

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

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

Ответ 7

У меня есть еще два бита для добавления:

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

Ответ 8

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

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

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

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

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

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

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

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

Я высокомерно прихожу к выводу, что модульное тестирование - это костыль для "плохих" кодовых баз, которые плохо испорчены и построены плохо?

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

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

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

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

Ответ 9

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

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