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

Кодирование кода тестирования модулей - есть ли у вас 100% -ый охват?

Выполняют ли ваши модульные тесты 100% -ное покрытие кода? Да или нет, и почему или почему нет.

4b9b3361

Ответ 1

Нет по нескольким причинам:

  • Достаточно дорого достичь покрытия 100% по сравнению с 90% или 95% для выгоды, которая не очевидна.
  • Даже при 100% охвате ваш код не идеален. Взгляните на этот метод (на самом деле это зависит от того, какой тип покрытия вы говорите - охват веток, покрытие линии...):


public static String foo(boolean someCondition) {
    String bar = null;
    if (someCondition) {
        bar = "blabla";
    }
    return bar.trim();
}

и unit test:

assertEquals("blabla", foo(true));

Тест будет успешным, и ваш код будет 100%. Однако, если вы добавите еще один тест:

assertEquals("blabla", foo(false));

то вы получите NullPointerException. И поскольку вы были на 100% с первым тестом, вы бы не обязательно записывали второй!

Как правило, я считаю, что код критический должен быть покрыт почти на 100%, а другой код может быть покрыт с 85-90%

Ответ 2

Для всех 90% тестеров покрытия:

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

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

Но также:

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

Ответ 3

Нет, потому что существует практический компромисс между идеальными модульными тестами и фактическим завершением проекта:)

Ответ 4

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

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

Ответ 5

Да, мы делаем.

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

Мы используем Ruby on Rails для моего текущего проекта. Ruby очень "макет" в том, что вы можете заглушить/измотать большие куски вашего кода, не создавая слишком сложную композицию класса и конструкции, которые вам нужно будет делать на других языках.

Тем не менее, у нас есть только 100% -ый охват линии (в основном, что дает вам rcov). Вам все равно придется думать о тестировании всех необходимых ветвей.

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

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

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

Делает ли это значение? Сначала я был настроен скептически, но я могу честно сказать, что да, да. Не в первую очередь потому, что вы тщательно протестировали код (хотя это определенно преимущество), но больше с точки зрения написания простого кода, который легко проверить и обосновать. Если вы знаете, что у вас должно быть 100% -ное покрытие, вы перестанете писать чрезмерно сложные, если /else/while/try/catch monstrosities и Keep It Simple Stupid.

Ответ 6

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

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

Поскольку он был в VC6 (С++ + MFC), я определил два макроса:

#define TCOV ASSERT(FALSE)
#define _COV ASSERT(TRUE)

а затем я посыпал

TCOV;

во всем коде, на каждом отдельном пути, который я мог найти, и в каждой рутине. Затем я запускал программу под отладчиком, и каждый раз, когда он попадал в TCOV, он останавливался. Я бы посмотрел на код для каких-либо очевидных проблем, а затем отредактировал его до _COV, а затем продолжу. Код будет перекомпилировать "на лету" и перейти к следующему TCOV. Таким образом, я медленно, кропотливо, устранил достаточно операторов TCOV, чтобы он работал "нормально".

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

public void method(boolean someBoolean) {
    if (someBoolean) {
        return;
    } else {
        /* do lots of stuff */ 
    }
}

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

Ответ 11

Из блога Теда Ньюарда.

К этому моменту большинство разработчиков, по крайней мере, слышали, если не считать принятие мема Masochistic Testing. Товарищи из NFJS Стюарт Халлоуэй и Джастин Гетланд основали консалтинговую фирму Relevance, которая устанавливает высокую планку в качестве корпоративного культурного стандарта: 100% тестирование покрытия их кода.

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

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

Ответ 12

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

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

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

Я хотел бы иметь одинаковые стандарты в отношении устаревших проектов, но я никогда не считал практичным приносить большое приложение со средним охватом до 100% охвата; Я должен был согласиться на 95-99%. Всегда было слишком много работы, чтобы вернуться и покрыть весь старый код. Это не противоречит моим аргументам, что легко хранить код на 100%; это намного проще, если вы поддерживаете этот стандарт с самого начала.

Ответ 13

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

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

Ответ 14

Да, у меня были проекты, у которых было 100% покрытие линии. См. Мой ответ на аналогичный вопрос .

Вы можете получать 100% покрытие линии, но, как другие указали здесь, на SO и в других местах в Интернете, это может быть только минимум. Когда вы рассматриваете путь и охват веток, вам предстоит еще много работы.

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

Ответ 15

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

Ключевой вопрос, который задают, - "какое влияние, если программное обеспечение терпит неудачу (приводит к неправильному результату)?". В большинстве случаев влияние ошибки относительно невелико. Например, возможно, вам придется исправить код в течение нескольких дней и повторить что-то. Однако, если воздействие "кто-то может умереть за 120 секунд", то это громадное влияние, и вы должны иметь гораздо больше тестового покрытия, чем просто покрытие на 100%.

Я возглавляю "Значок наилучшей практики инициации базовой инфраструктуры" для Linux Foundation. У нас есть покрытие на 100%, но я бы не сказал, что это строго необходимо. Долгое время мы были очень близки к 100%, и просто решили сделать этот последний небольшой процент. Однако мы не смогли оправдать последние несколько процентов на инженерных площадках; эти последние несколько процентов были добавлены исключительно как "гордость за мастерство" . Я получаю очень маленький лишний кусок ума от покрытия на 100%, но на самом деле он не нужен. У нас было более 90% заявлений на участие только от обычных тестов, и это было хорошо для наших целей. Тем не менее, мы хотим, чтобы программное обеспечение было устойчивым, а 100% охват заявлений помог нам туда добраться. Кроме того, сегодня легче получить 100% заявлений.

По-прежнему полезно измерять охват, даже если вам не нужно 100%. Если ваши тесты не имеют надлежащего покрытия, вы должны быть обеспокоены. Плохой набор тестов может иметь хорошее покрытие для операторов, но если у вас нет хорошего покрытия операторов, то по определению у вас плохой набор тестов. Насколько вам нужен компромисс: каковы риски (вероятность и влияние) от полностью непроверенного программного обеспечения? По определению у него больше шансов иметь ошибки (вы его не тестировали!), Но если вы и ваши пользователи можете жить с этими рисками (вероятность и воздействие), все в порядке. Для многих проектов с меньшим воздействием я считаю, что охват заявлений на 80% -90% в порядке, причем лучше быть лучше.

С другой стороны, если люди могут умереть от ошибок в вашем программном обеспечении, то 100% охвата заявлений недостаточно. Я бы, по крайней мере, добавил покрытие веток и, возможно, больше, чтобы проверить качество ваших тестов. Стандарты, такие как DO-178C (для бортовых систем) используют такой подход - если сбой является незначительным, не имеет большого значения, но если сбой может быть катастрофическим, тогда требуется более тщательное тестирование. Например, DO-178C требует охвата MC/DC для наиболее критического программного обеспечения (программного обеспечения, которое может быстро убить людей, если оно совершит ошибку), MC/DC является более напряженным, чем покрытие оператора или даже охват веток.

Ответ 16

Здесь много полезной информации, я просто хотел добавить еще несколько преимуществ, которые я нашел, стремясь к 100% охвату кода в прошлом

  • Это помогает уменьшить сложность кода

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

  • Это помогает развить хорошую гранулярность теста

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

Ответ 17

Некоторое время назад я немного проанализировал охват реализации JUnit, кода, написанного и протестированного, среди прочего, Кентом Беком и Дэвидом Саффом.

Из выводов:

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

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

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

  3. Нет причин иметь методы с более чем 2-3 непроверенными строками кода.

  4. Обычные подозреваемые (простой код, мертвый код, поведение при плохой погоде и т.д.) Соответствуют примерно 5% раскрытого кода.

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