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

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

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

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

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

Итак, с TDD,

  • Я начну с создания unit test BooksLimit(), который сохранит две сотни книг в базе данных, вызовет DisplayBooks() и сделает Assert.AreEqual(100, DisplayedBooks.Count).
  • Затем я буду проверять, не сработает ли он,
  • Затем я изменю DisplayBooks(), установив предел результатов на 100 и
  • Наконец, я повторю тест, чтобы убедиться, что он преуспел.

Ну, не намного ли проще перейти на третий шаг и вообще не сделать BooksLimit() unit test? И не более ли это Agile, когда требования будут меняться от 100 до 200 ограничений книг, чтобы изменить только один символ, вместо того, чтобы менять тесты, запускать тесты, чтобы проверить, не сработает ли он, изменить код и выполнить тесты еще раз, чтобы проверить, удалось ли это?

Примечание. Предположим, что код полностью задокументирован. В противном случае некоторые могут сказать, и они будут правы, что выполнение полных модульных тестов поможет понять код, в котором отсутствует документация. Фактически, наличие BooksLimit() unit test будет очень четко показывать, что для отображения будет максимальное количество книг и что это максимальное число равно 100. Переход на код не-unit-тестов будет намного сложнее, поскольку такой предел может быть реализован, хотя for (int bookIndex = 0; bookIndex < 100; ... или foreach ... if (count >= 100) break;.

4b9b3361

Ответ 1

Ну, не намного ли проще перейти на третий шаг и вообще не делать BooksLimit() unit test?

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

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

Что касается упрощения обслуживания: NO WAY! Я не могу использовать это достаточно.

Если вы единственный человек, который когда-либо работал над вашим проектом, то да, вы можете подумать. Но этот безумный разговор! Постарайтесь встать на скорость по проекту на 30 тыс. Строк без unittests. Попытайтесь добавить функции, требующие значительных изменений кода без 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% -ное покрытие для тестирования отличное, но это не означает, что ваше программное обеспечение идеально подходит. Все сводится к уверенности перед лицом перемен.

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

ОК, собираюсь написать еще несколько тестов...

Ответ 2

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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

Ответ 5

Я согласен с @soru, 100% -ное охват тестирования не является разумной целью.

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

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

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

Обратите внимание, что цель состоит в том, чтобы найти 100% ошибок, а не находить 100% -ный охват.

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

Ответ 6

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

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

Ну, не намного ли проще перейти на третий шаг и вообще не делать BooksLimit() unit test?

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

Ответ 7

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

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

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

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

Ответ 8

Извините за мой английский.

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

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

Требуется ли 100% -ное покрытие кода?