Какие могут быть альтернативные метрики для покрытия кода?
Покрытие кода является Propably наиболее спорным код метрики. Некоторые говорят, что вы должны достичь 80% покрытия кода, другие говорят, что это поверхностно и ничего не говорит о качестве вашего тестирования. (См . Хороший ответ Джона Лимджапа "Какой разумный процент покрытия кода для модульных тестов (и почему)?".)
Люди стремятся все измерить. Им нужны сравнения, тесты и т. Д.
Проектным командам нужен указатель, насколько хорошо их тестирование.
Так, каковы альтернативы покрытию кода? Что может быть хорошим показателем, который говорит больше, чем "Я коснулся этой строки кода"?
Есть ли реальные альтернативы?
14 ответов
Если вы ищете некоторые полезные метрики, которые сообщают вам о качестве (или его отсутствии) вашего кода, вам следует рассмотреть следующие метрики:
- Цикломатическая Сложность
- Это мера того, насколько сложный метод.
- Обычно 10 и ниже - хорошо, 11-25 - плохо, выше - ужасно.
- Глубина вложения
- Это показатель количества вложенных областей в методе.
- Обычно 4 и ниже - хорошо, 5-8 - плохо, выше - ужасно.
- Реляционная сплоченность
- Это показатель того, насколько хорошо связаны типы в пакете или сборке.
- Реляционная сплоченность является в некоторой степени относительной метрикой, но тем не менее полезной.
- Приемлемые уровни зависят от формулы. Учитывая следующее:
- R: количество отношений в упаковке / сборке
- N: количество типов в упаковке / сборке
- H: сплоченность отношений между типами
- Формула: H = (R+1)/N
- Учитывая приведенную выше формулу, приемлемый диапазон составляет 1,5 - 4,0.
- Отсутствие сплоченности методов (LCOM)
- Это мера того, насколько сплочен класс.
- Сплоченность класса - это показатель количества полей, на которые ссылается каждый метод.
- Хороший показатель того, соответствует ли ваш класс принципалу единоличной ответственности.
- Формула: LCOM = 1 - (сумма (MF) / M * F)
- M: количество методов в классе
- F: количество полей экземпляра в классе
- MF: количество методов в классе, обращающихся к конкретному полю экземпляра
- сумма (MF): сумма MF по всем полям экземпляра
- Класс, который является полностью связным, будет иметь LCOM 0.
- Класс, который является полностью несвязным, будет иметь LCOM 1.
- Чем ближе к 0 вы подходите, тем более сплоченный и обслуживаемый класс.
Это лишь некоторые из ключевых метрик, которые NDepend, утилита для отображения метрик.NET и зависимости, может предоставить вам. Недавно я много работал с метриками кода, и эти 4 метрики являются основными ключевыми метриками, которые мы сочли наиболее полезными. Тем не менее, NDepend предлагает несколько других полезных показателей, в том числе Efferent & Afferent connection и Abstractness & Instability, которые в совокупности обеспечивают хорошую меру того, насколько поддерживаемым будет ваш код (и независимо от того, называете ли вы то, что NDepend называет зоной боли или зоной Бесполезность.)
Даже если вы не работаете с платформой.NET, я рекомендую взглянуть на страницу метрик NDepend. Там есть много полезной информации, которую вы можете использовать для вычисления этих метрик на любой платформе, на которой вы разрабатываете.
Crap4j - одна из довольно хороших метрик, о которых я знаю...
Это Java-реализация метрики программного обеспечения "Анализ рисков и прогнозы изменений", которая сочетает в себе цикломатическую сложность и охват кода автоматическими тестами.
Сценарий покрытия.
Я не думаю, что вы действительно хотите иметь 100% покрытие кода. Тестирование говорит, что простые геттеры и сеттеры выглядят как пустая трата времени.
Код всегда выполняется в каком-то контексте, поэтому вы можете перечислить как можно больше сценариев (в зависимости от сложности проблемы, иногда даже всех) и протестировать их.
Пример:
// parses a line from .ini configuration file
// e.g. in the form of name=value1,value2
List parseConfig(string setting)
{
(name, values) = split_string_to_name_and_values(setting, '=')
values_list = split_values(values, ',')
return values_list
}
Теперь у вас есть много сценариев для тестирования. Некоторые из них:
Передача правильного значения
Элемент списка
Проходя ноль
Передача пустой строки
Передача неформатированного параметра
Передача строки с начальной или конечной запятой, например, name = value1 или name=,value2
Запуск только первого теста может дать вам (в зависимости от кода) 100% покрытия кода. Но вы не учли все возможности, так что сама по себе метрика мало о чем говорит.
Метрики ошибок также важны:
- Количество ошибок, поступающих
- Количество исправленных ошибок
Например, чтобы определить, устраняются ли ошибки так быстро, как приходят новые.
Code Coverage - это просто индикатор, который помогает указать на строки, которые вообще не выполняются в ваших тестах, что довольно интересно. Если вы достигаете 80% покрытия кода или около того, имеет смысл взглянуть на оставшиеся 20% строк, чтобы определить, пропускаете ли вы какой-либо вариант использования. Если вы видите "ага, эта строка будет выполнена, если я пропущу пустой вектор", тогда вы можете написать тест, который пройдет пустой вектор.
В качестве альтернативы я могу подумать, что если у вас есть документ с техническими характеристиками с вариантами использования и функциональными требованиями, вы должны сопоставить им модульные тесты и посмотреть, сколько UC покрыто FR (конечно, это должно быть 100%) и сколько FR покрыты UT (опять же, это должно быть 100%).
Если у вас нет спецификаций, кого это волнует? Все, что случится, будет в порядке:)
А как насчет отслеживания тенденции покрытия кода во время вашего проекта?
Как и в случае со многими другими показателями, одно число не говорит о многом.
Например, трудно сказать, есть ли проблема, если "у нас соответствие правилам Checkstyle 78,765432%". Если вчерашнее соблюдение было 100%, у нас определенно проблемы. Если вчера было 50%, мы, вероятно, делаем хорошую работу.
Я всегда нервничаю, когда покрытие кода становится все меньше и меньше с течением времени. Есть случаи, когда это нормально, поэтому вы не можете выключить голову, глядя на диаграммы и цифры.
Кстати, сонар ( http://sonar.codehaus.org/) - отличный инструмент для отслеживания тенденций.
Использование покрытия кода само по себе бессмысленно, оно дает вам только понимание, если вы ищете ненужный код.
Использование его вместе с юнит-тестами и стремление к 100% охвату скажут вам, что все "проверенные" детали (предполагается, что все было также успешно) работают так, как указано в юнит-тесте.
Написание юнит-тестов из технического проекта / функционального проекта, со 100% охватом и 100% успешными тестами скажет вам, что программа работает так, как описано в документации.
Теперь единственное, что вам нужно, это хорошая документация, особенно функциональный дизайн, программист не должен писать, что если он не является экспертом в этой конкретной области.
Я написал сообщение в блоге о том, почему Высокий коэффициент охвата тестов - хорошая вещь.
Я согласен с тем, что: когда часть кода выполняется тестами, это не означает, что достоверность результатов, полученных этой частью кода, проверяется тестами.
Но, тем не менее, если вы интенсивно используете контракты для проверки достоверности состояний во время выполнения тестов, высокий уровень охвата тестами в любом случае будет значительным подтверждением.
Это не было упомянуто, но количество изменений в данном файле кода или метода (глядя на историю контроля версий) особенно интересно, когда вы создаете набор тестов для плохо протестированного кода. Сосредоточьте свое тестирование на частях кода, которые вы сильно изменили. Оставьте те, которые вы не делаете на потом.
Не упустите причину и следствие. Вы можете избежать изменения непроверенного кода, и вы можете изменить проверенный код больше.
Как правило, скорости внедрения дефектов пропорционально следуют за кодом, и они оба обычно следуют кривой распределения Рэлея.
В какой-то момент ваша скорость обнаружения дефектов достигнет максимума, а затем начнет уменьшаться.
Эта вершина представляет 40% обнаруженных дефектов.
Продвигаясь вперед с помощью простого регрессионного анализа, вы можете оценить, сколько дефектов осталось в вашем продукте в любой точке после пика.
Это один из компонентов модели Лоуренса Патнэма.
Значение в покрытии кода - это дает вам некоторое представление о том, что было выполнено тестами. Фраза "покрытие кода" часто используется для обозначения покрытия оператора, например, "сколько моего кода (в строках) было выполнено", но на самом деле существует более сотни разновидностей "покрытия". Эти другие версии охвата пытаются дать более сложное представление о том, что значит использовать код.
Например, условие покрытия измеряет, сколько отдельных элементов условных выражений было выполнено. Это отличается от покрытия заявления. MC/DC "измененное условие / покрытие принятия решения" определяет, были ли продемонстрированы все элементы всех условных выражений для управления результатом условного выражения, и это требуется FAA для программного обеспечения самолета. Покрытие пути измеряет, сколько возможных путей выполнения вашего кода было выполнено. Это лучшая мера, чем охват операторов, поскольку пути по сути представляют разные случаи в коде. Какие из этих мер лучше всего использовать, зависит от того, насколько вы обеспокоены эффективностью ваших тестов.
Википедия достаточно хорошо обсуждает многие варианты тестового покрытия. http://en.wikipedia.org/wiki/Code_coverage
Как насчет (строк кода)/(количество тестов)? Не очень значимый (так как это зависит от LOC), но по крайней мере это легко вычислить.
Другой может быть (количество тестовых случаев)/(количество методов).
SQLite является чрезвычайно хорошо протестированной библиотекой, и вы можете извлечь из нее все виды метрик.
Начиная с версии 3.6.14 (все статистические данные в отчете соответствуют этой версии SQLite), библиотека SQLite состоит из приблизительно 63,2 KSLOC кода C. (KSLOC означает тысячи "строк исходного кода" или, другими словами, строк кода, исключая пустые строки и комментарии.) Для сравнения, в проекте в 715 раз больше тестового кода и тестовых сценариев - 45261,5 KSLOC.
В конце концов, что всегда кажется мне наиболее значимым, так это то, что ни одна из этих возможных метрик не кажется столь же важной, как простое утверждение: "оно соответствует всем требованиям". (Так что не упускайте из виду эту цель в процессе ее достижения.)
Если вы хотите что-то, чтобы судить о прогрессе команды, вы должны установить индивидуальные требования. Это дает вам что-то, на что можно указать и сказать: "Это сделано, это не так". Он не является линейным (решение каждого требования потребует различной работы), и вы можете линеаризовать его единственным способом, если проблема уже была решена в другом месте (и, таким образом, вы можете квантовать работу по требованию).
Мне нравится выручка, цифры продаж, прибыль. Это довольно хорошие метрики кодовой базы.
Вероятно, не только для измерения кода, охваченного (затронутого) модульными тестами, но и для оценки того, насколько хороши утверждения.
Одна метрика, которую легко реализовать, - это измерение размера Assert.AreEqual
Вы можете создать свой собственный вызов реализации Assert Assert.AreEqual
и измерение размера объекта, переданного в качестве второго параметра.