Является ли 100% покрытие кода несбыточной мечтой?

28

Можно ли ожидать 100% покрытия кода в тяжелых веб-приложениях jquery / backbonejs? Разумно ли проваливать спринт из-за 100% покрытия, которое не выполняется, когда фактическое покрытие кода колеблется около 92% -95% в javascript / jquery?

willz
источник
7
«Неудачный спринт» звучит странно зловеще…
Донал Феллоуз
5
Это асимптота.
Роберт Харви
12
даже если у вас есть полное покрытие, некоторые ошибки не будут найдены, так что не полагайтесь на это число, чтобы исправить все
трещотка урод
11
Все возможно. Реальный вопрос заключается в том, стоит ли значение 100% покрытия кода затратами времени и ресурсов.
JohnFx
5
Почему вы беспокоитесь об этом, когда основополагающее предположение - что 100% (или любое другое число) автоматизированное тестовое покрытие волшебным образом улучшит ваш код - само по себе несбыточная мечта?
Мейсон Уилер

Ответы:

30

Это так же реалистично, как и нереально.

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

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

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

Мы не знаем влияния неудачи на ваш проект, поэтому мы не можем сказать, достаточно ли 92% или 95%, или если эти 100% действительно необходимы. Или в этом отношении, 100% полностью проверяет все, что вы ожидаете.


источник
30
... И только то, что у вас 100% покрытие кода, не означает, что у вас 100% покрытие ветви, поэтому даже при 100% покрытии кода вы можете пропустить много.
Брайан Оукли
3
+1 за размер проекта. Разбиение на более мелкие, многократно используемые и тестируемые компоненты позволило нам самим охватить ~ 95%. 100% покрытие не обязательно. Интеграционное тестирование должно покрывать пробелы в модульном тестировании.
Апурв Хурасия
5
@BryanOakley ... и ваши тесты могут быть бессмысленными, или вообще ничего не тестировать
David_001
5
@BryanOakley И даже при 100% покрытии ветвей, возможно, что определенная комбинация ветвей может вызвать проблемы. (например, два последовательных оператора IF могут быть разветвлены и разделены в отдельных тестах, но при этом отсутствует тест, включающий оба . Полный охват ветви, но пропущен один путь выполнения)
Izkata
4
Даже 100% покрытия веток, включая все пути выполнения, недостаточно. Может быть, какая-то ошибка возникает только тогда, когда вы берете какую-то комбинацию веток и у вас есть какой-то внешний ввод, скажем, неправильная дата. Нет никакой возможности, что все случаи когда-либо будут покрыты. В то же время можно быть уверенным с охватом менее 100%, но подходящим образом выбранными граничными случаями в качестве входных данных.
Андреа
32

Кто тестирует тесты?

Это очень наивно в лучшем случае и нереально даже в теоретическом смысле и непрактично в деловом смысле.

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

Тестирование каждой строки кода не является хорошей целью

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

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

Проблема остановки:

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

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

Поскольку вы даже не можете доказать, что что-то работает на 100%, зачем делать это своей целью?

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


источник
7
это действительно должен быть принятый ответ. 100% покрытие кода почти так же плохо, как 0%.
Ryathal
1
«Слишком много переменных, чтобы охватить каждую комбинацию». Это не имеет ничего общего с получением 100% покрытия кода. Если строка кода была достаточно важна для написания, и она достаточно важна, чтобы ее можно было сохранить, тогда она достаточно важна, чтобы ее охватил тест. Если тест не охватывается, единственное безопасное допущение - он не работает. Это правда, что для некоторого кода нет смысла тестировать его с точки зрения бизнеса. Это тот самый код, который не имеет смысла с точки зрения бизнеса писать.
still_dreaming_1
2
Таким образом, вы думаете, что написание тестовых случаев, охватывающих простые или getXXX()/setXXX()простые конструкторы присваивания для объектов-значений, - это хорошее использование времени и ресурсов, извините, что это не совсем так в действительности, и крайне наивное мнение, которому не хватает реального опыта для его поддержки. Помните, что тестовый код - это код, который необходимо поддерживать. Чем меньше кода вы пишете для решения проблемы, тем лучше в каждом случае .
Хм "Это нереально с кодом, который имеет высокую цикломатическую сложность. Слишком много переменных, чтобы охватить каждую комбинацию". - конечно, именно поэтому вы должны разбивать такой код на более мелкие части, которые имеют небольшую цикломатическую сложность и, следовательно, легче тестируются. Рефакторинг таким образом важен для тестирования - он облегчает тестирование.
Предраг Стоядинович
17

В большинстве случаев 100% покрытие кода означает, что вы немного «обманули»:

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

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

Дэн Монего
источник
Как движется к обману DSL?
back2dos
2
@ back2dos - Хотя вы можете использовать модульный тест, скажем, встроенные скрипты Python, вы, скорее всего, не проводите модульное тестирование своих HTML-шаблонов или CSS или подсчет строк в них в направлении оценки покрытия.
Дан Монего
12

Впечатляющий, реальный пример 100% охвата веток см. В разделе Как тестируется SQLite .

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

Брайан Оукли
источник
9

100% покрытие кода для модульных тестов для всех частей конкретного приложения - несбыточная мечта, даже с новыми проектами. Хотелось бы, чтобы это было так, но иногда вы просто не можете охватить кусок кода, независимо от того, как сильно вы пытаетесь абстрагироваться от внешних зависимостей. Например, предположим, что ваш код должен вызывать веб-сервис. Вы можете скрыть вызовы веб-службы за интерфейсом, чтобы смоделировать эту часть и проверить бизнес-логику до и после веб-службы. Но фактическая часть, которая должна вызвать веб-сервис, не может быть проверена модулем (в любом случае, очень хорошо). Другой пример, если вам нужно подключиться к TCP-серверу. Вы можете скрыть код, который подключается к TCP-серверу за интерфейсом. Но код, который физически подключается к серверу TCP, не может быть проверен модулем, потому что, если он по какой-либо причине не работает, это может привести к сбою модульного теста. И модульные тесты должны всегда проходить, независимо от того, когда они вызываются.

Хорошее практическое правило - вся ваша бизнес-логика должна иметь 100% покрытие кода. Но части, которые должны вызывать внешние компоненты, должны иметь максимально приближенное к 100% покрытие кода. Если ты не сможешь достичь, я бы не стал слишком потеть.

Гораздо важнее, правильны ли тесты? Они точно отражают ваш бизнес и требования? Наличие покрытия кода только наличием покрытия кода ничего не значит, если все, что вы делаете, это тестирование неправильно или тестирование неверного кода. При этом, если ваши тесты хороши, то охват 92-95% является выдающимся.

bwalk2895
источник
1
Тестирование того, что происходит, когда вы получаете странные комбинации случаев ошибок и отказов на ответ, может быть исключительно сложным.
Donal Fellows
Разве понимание того, что будет делать ваша система, когда она сталкивается с этими сложными проблемами, не является частью привлекательности модульного тестирования? Также здесь есть некоторая путаница между юнит-тестами и интеграционными тестами.
Питер Смит
Это связано unit testingс тем integration testing, что тестирование кода, который вы не написали, является integrationтестированием. Стек TCP находится в ОС, которую вы не должны тестировать, вы должны предположить, что он уже протестирован тем, кто когда-либо писал его.
4

Я бы сказал, что если код не разработан с конкретной целью обеспечения 100% покрытия тестами, 100% может оказаться недостижимым. Одна из причин может заключаться в том, что если вы защищаете код - что вам следует - у вас должен иногда быть код, который обрабатывает ситуации, которые, как вы уверены, не должны происходить или не могут происходить, учитывая ваши знания о системе. Покрыть такой код тестами было бы очень сложно по определению. Отсутствие такого кода может быть опасным - что, если вы ошибаетесь, и такая ситуация случается один раз из 256? Что если в несвязанном месте произошли изменения, которые делают невозможное невозможным? И т. Д. Таким образом, 100% может быть довольно трудно достичь "естественными" средствами - например, если у вас есть код, который выделяет память, и у вас есть код, который проверяет, не сработал ли он, если вы не макете менеджер памяти (что может быть непросто) и написать тест, который возвращает «недостаточно памяти», охватывая этот код может быть сложно. Для приложения JS это может быть защитное кодирование вокруг возможных причуд DOM в разных браузерах, возможных сбоев внешних служб и т. Д.

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

StasM
источник
Тот факт, что код не должен запускаться в производственном режиме при нормальных обстоятельствах, не означает, что он не может быть написан таким образом, чтобы его выполняли тесты. Насколько важно, чтобы этот необычный код работал правильно? Достаточно ли важно покрыть это тестами? Я бы сказал, что если это не так важно, чтобы охватить тестами, это не так важно, чтобы справиться с этим делом. Код, который не нуждается в тестах, - это код, который не должен существовать и должен быть удален.
still_dreaming_1
2

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

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

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

Разумно ли проваливать спринт из-за 100% покрытия, которое не выполняется, когда фактическое покрытие кода колеблется около 92% -95% в javascript / jquery?

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

S.Robins
источник
«Извините, но вы просто не можете получить это в обоих направлениях без компромисса». Это неправда. Вы всегда можете уменьшить масштаб функций или идти медленнее. Если что-то не стоит тестировать, не стоит писать. Если строка кода достаточно важна, чтобы ее хранить, она достаточно важна для тестирования. Если это не так важно, чтобы проверить, это не так важно, чтобы держать вокруг. Единственное безопасное предположение о том, что строка кода не проверена, это то, что она не работает.
still_dreaming_1
@ still_dreaming_1, вы, кажется, поддержали мое заявление и противоречили себе. Сокращение возможностей или изменение ваших сроков - это компромиссы, каждый из которых может повлиять на стоимость проекта и ожидания заинтересованных сторон. Тестирование унаследованного кода, который ранее не был полностью протестирован, чрезвычайно сложно, так как вы должны понимать не только код во время его выполнения, но и намерения исходного создателя, и написание тестов, которые фиксируют поведение существующего унаследованного кода, не обязательно показывает что код работает полностью как положено.
С.Робинс,
Я предполагаю, что моя точка зрения заключалась в том, что то, что было скомпрометировано, функции или изменения, которые еще не были созданы из-за того, что разработка идет быстрее, не является реальным компромиссом, потому что если вы потеряете покрытие, чтобы двигаться быстрее, эти функции и изменения могут только предполагается, что не работает правильно в любом случае. Тогда какой смысл вносить эти изменения или добавлять эти функции, если не имеет значения, работают они правильно или нет? Если не имеет значения, работают они правильно или нет, эти изменения не нужно было вносить, и теперь их нужно вытащить из кода.
still_dreaming_1
Я больше не верю в это, или, по крайней мере, я осознаю практический аспект истины, которую вы говорите, особенно в унаследованной кодовой базе, так что это всего лишь объяснение того, что я пытался сделать в то время. На самом деле, я сейчас совершенно не согласен с тем, чтобы даже делать TDD все время на новой кодовой базе, не говоря уже о получении 100% покрытия. С одной стороны, каждая форма логики и разума говорит мне, что обе эти вещи должны быть хорошими, и все же на практике я не могу сделать это практичным. Что-то не так с миром программирования, нам нужна новая парадигма.
still_dreaming_1
1

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

Есть ли какое-то конкретное препятствие, с которым вы сталкиваетесь, мешающее вам попасть в эти последние несколько строк? Если нет, если получение от 95% до 100% покрытия является простым, так что вы можете пойти и сделать это. Так как вы здесь спрашивать, я буду считать , что это что - то. Что это такое?

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

92% в порядке. Я чувствую, что настоящие вопросы:

  • Является ли 92% «новой» нормой сейчас? Если у следующего спринта будет 88% тестов, это будет хорошо? Это часто начало заброшенных наборов тестов.

  • Насколько важно, чтобы программное обеспечение работало и не имело ошибок. У вас есть тесты по этим причинам, а не "ради тестирования"

  • Есть ли план вернуться и заполнить пропущенные тесты?

  • Почему ты тестируешь? Кажется, что фокус -% покрытой линии, а не функциональность

Майкл Даррант
источник
«Насколько важно, чтобы программное обеспечение работало и не имело ошибок»? Хороший вопрос. Каково определение ошибки? То, что не работает, как задумано. Если какой-то код работает неправильно, не пишите его. Весь смысл кода в том, чтобы он работал.
still_dreaming_1
0

Мартин Фаулер пишет в своем блоге :I would be suspicious of anything like 100% - it would smell of someone writing tests to make the coverage numbers happy, but not thinking about what they are doing.

Тем не менее, существуют даже стандарты, которые предусматривают 100% охват на уровне подразделений. Например, это одно из требований стандартов европейского космического полета (ECSS, Европейское сотрудничество по стандартизации космоса). Связанный здесь документ рассказывает интересную историю проекта, целью которого было достичь 100% покрытия тестами в уже готовом программном обеспечении. Он основан на беседах с вовлеченными инженерами, которые разработали модульные тесты.

Некоторые из уроков:

  • 100% покрытие необычно, но достижимо
  • Иногда необходимо 100% покрытие
  • 100% покрытие приносит новые риски
  • Не оптимизировать для 100% -метрических
  • Разработать правильную стратегию для максимального охвата
  • 100% покрытие не является достаточным условием для хорошего качества
user6681109
источник
0

Возможно, вопрос о том, является ли это возможным и разумным, не самый полезный вопрос. Вероятно, самый практичный ответ - принятый. Я проанализирую это на более философском уровне.

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

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

Достижение 100% покрытия кода - противоестественный акт. Для большинства людей принуждение их к достижению этого было бы формой пытки.

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

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

Вот пара попыток сделать кодирование более естественным:

https://github.com/jcoplien/trygve

https://github.com/still-dreaming-1/PurposefulPhp

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

still_dreaming_1
источник
-2

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

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

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

Книга Майкла Фезера « Эффективная работа с устаревшим кодом » была для нас неоценима, поскольку мы разработали стратегии добавления тестов в наш устаревший код.

Ричард Уэллс
источник
-3

Нет, это невозможно и никогда не будет. Если бы это было возможно, вся математика впала бы в финитизм. Например, как бы вы протестировали функцию, которая взяла два 64-битных целых числа и умножила их? Это всегда было моей проблемой с тестированием, а не с проверкой правильности программы. Для чего угодно, кроме самых тривиальных программ, тестирование в основном бесполезно, поскольку охватывает лишь небольшое количество случаев. Это все равно что проверить 1000 номеров и сказать, что вы доказали гипотезу Гольдбаха.

veryfoolish
источник
Ой! Поэтому кто-то расстроен, что я не ответил на проблему в плане ее концепции; тестирование - пустая трата времени. Мне все равно, популярно ли оно. Это никогда не сработает. Оно не может. Это знали самые умные компьютерные ученые (Дейкстра, Кнут, Хоар и др.). Я предполагаю, что если вы программист на JavaScript, раздражающий eXtreme Programming, то вам все равно, что за эти проблемы. Бла, что угодно, кого это волнует ... пишите дерьмовый код. Отходы CO ^ 2 при проведении ваших испытаний. - Я имею в виду, у кого есть время сидеть и думать больше? Мы экспортировали это на компьютер.
глупо
3
Вопрос с тегом «TDD». TDD - больше инструмент проектирования и инструмент исследования проблем, чем тестирование, и каждый «тест» - это всего лишь пример того, как код будет вести себя в каком-то контексте, так что люди могут прочитать и понять, что происходит, а затем безопасно изменить его. , Хорошо выполненный TDD ведет к созданию более чистого и удобного в использовании кода, а выполнение тестов просто проверяет актуальность документации. Большинство TDD-комплектов почти никогда не обнаруживают ошибок; это не то, для чего они там. Я думаю, что вас опускают, потому что ваш ответ выдает отсутствие понимания, и я надеюсь, что этот комментарий поможет в этом.
Лунивор