Действительно ли 100%-е покрытие кода является действительно хорошей вещью при выполнении модульных тестов? [закрытый]

28
задан rmtheis 4 May 2015 в 04:32
поделиться

7 ответов

А не проще ли сразу перейти к третьему шагу и вообще не делать юнит-тест BooksLimit()?

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

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

Что касается усложнения сопровождения: НИ В КОЕМ СЛУЧАЕ! Я не могу выразить это с большой буквы.

Если вы единственный человек, который когда-либо работал над вашим проектом, то да, вы можете так думать. Но это бред! Попробуйте войти в курс дела в проекте на 30 тысяч строк без нетестов. Попробуйте добавить функции, требующие значительных изменений в коде, без unittests. Нет никакой уверенности, что вы не нарушите неявные предположения, сделанные другими инженерами. Для сопровождающего (или нового разработчика в существующем проекте) unittests - ключевой момент. Я опирался на unittests для документации, для поведения, для предположений, для подсказки мне, когда я что-то сломал (что я считал несвязанным). Иногда плохо написанный API имеет плохо написанные тесты и может стать кошмаром для изменений, потому что тесты отнимают все ваше время. В конце концов, вы захотите рефакторить этот код и исправить это, но ваши пользователи скажут вам спасибо и за это - ваш API станет намного проще в использовании благодаря этому.

Замечание о покрытии:

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

// Will return a number less than or equal to 3
int Bar(bool cond1, bool cond2) {
  int b;
  if (cond1) {
    b++;
  } else {
    b+=2;
  }

  if (cond2) {
    b+=2;
  } else {
    b++;
  }
}

Теперь представьте, что я пишу тест, который проверяет:

EXPECT_EQ(3, Bar(true, true));
EXPECT_EQ(3, Bar(false, false));

Это 100% покрытие. Это также функция, которая не соответствует контракту - Bar(false, true); не работает, потому что возвращает 4. Так что "полное покрытие" не является конечной целью.

Честно говоря, я бы пропустил тесты для BooksLimit(). Он возвращает константу, так что, вероятно, не стоит тратить время на их написание (и его следует тестировать при написании DisplayBooks()). Я могу огорчиться, когда кто-то решит (неправильно) вычислить этот предел из размера полки, и он перестанет удовлетворять нашим требованиям. Я и раньше обжигался на "не стоит тестировать". В прошлом году я написал код, о котором сказал своему коллеге: "Этот класс - в основном данные, его не нужно тестировать". У него был метод. В нем был баг. Он пошел в производство. Он вызвал нас посреди ночи. Я чувствовал себя глупо. Поэтому я написал тесты. А потом я долго размышлял о том, какой код является "не стоящим тестирования". Их не так много.

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

Если я соберу класс A, класс B и класс C вместе и найду что-то, что не работает, хочу ли я тратить время на отладку всех трех? Нет. Я хочу знать, что A и B уже выполнили свои контракты (через unittests), а мой новый код в class C, вероятно, сломан. Поэтому я его проверяю. Как я узнаю, что он сломан, если я не проведу проверку? Нажав на несколько кнопок и попробовав новый код? Это хорошо, но недостаточно. Когда ваша программа увеличится, будет невозможно повторно запустить все ручные тесты, чтобы проверить, что все работает правильно. Вот почему люди, использующие unittest, обычно автоматизируют и запуск своих тестов. Скажите мне "Pass" или "Fail", не говорите мне "на выходе получается ...".

Хорошо, пойду напишу еще несколько тестов...

33
ответ дан 28 November 2019 в 02:57
поделиться

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

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

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

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

6
ответ дан 28 November 2019 в 02:57
поделиться

Трудно получить первые 100%, особенно в больших проектах! и даже если вы это сделаете, когда блок кода покрыт, это не означает, что он делает то, что должен, если только ваш тест не утверждает все возможные входные и выходные данные (что почти невозможно).

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

Что ж, не намного ли проще перейти непосредственно к третьему шагу и вообще никогда не проводить модульный тест BooksLimit ()?

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

1
ответ дан 28 November 2019 в 02:57
поделиться

Не существует однозначной связи между покрытием кода и хорошим программным обеспечением. Вы можете легко представить себе кусок кода со 100% (или близким) покрытием кода, который все еще содержит множество ошибок. (Что не означает, что тесты плохие!)

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

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

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

Психологическим побочным эффектом "100% покрытия кода" является то, что вы можете думать, что в вашем коде нет ошибок, что никогда не бывает правдой:)

.
5
ответ дан 28 November 2019 в 02:57
поделиться

Я согласен с @soru, 100% покрытие тестами не является рациональной целью.

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

Хотя его диссертация была принята, и сейчас он является профессором в крупной инженерной школе, он не нашел ни:

1) магического числа покрытия тестами, которое является оптимальным 2) ни одного набора тестов, который мог бы найти 100% ошибок.

Заметьте, цель - найти 100% ошибок, а не найти 100% покрытие.

Правильно ли 85% @soru или нет - это предмет для обсуждения. У меня нет возможности оценить, было бы лучшим числом 80%, 90% или что-то еще. Но в качестве рабочей оценки 85% мне кажется правильным.

2
ответ дан 28 November 2019 в 02:57
поделиться

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

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

Для другого приведенного вами примера рекомендуется проверить граничные значения. Таким образом, вы можете ограничить свои тесты только четырьмя значениями: 0, какое-то магическое число от 0 до BooksLimit, BooksLimit и некоторое число выше.

И, как говорили другие, делайте тесты, но быть на 100% положительным, что-то другое может не сработать.

0
ответ дан 28 November 2019 в 02:57
поделиться

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

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

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

12
ответ дан 28 November 2019 в 02:57
поделиться
Другие вопросы по тегам:

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