Покрытие кода - Code coverage

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

Тестовое покрытие было одним из первых методов, изобретенных для систематического тестирования программного обеспечения . Первое опубликованное упоминание было сделано Миллером и Мэлони в Коммуникациях ACM в 1963 году.

Критерии охвата

Чтобы измерить, какой процент кода был использован набором тестов , используется один или несколько критериев покрытия . Критерии покрытия обычно определяются как правила или требования, которым должен удовлетворять набор тестов.

Основные критерии покрытия

Существует ряд критериев покрытия, основными из которых являются:

  • Охват функций  - вызывалась ли каждая функция (или подпрограмма ) в программе?
  • Покрытие операторов  - каждый оператор в программе был выполнен?
  • Покрытие ребер  - каждое ребро в графе потока управления выполнено?
  • Покрытие ветвей  - выполнялась ли каждая ветвь (также называемая DD-путем ) каждой управляющей структуры (например, в операторах if и case )? Например, для данного оператора if были выполнены как истинная, так и ложная ветвь? Это подмножество покрытия краев.
  • Покрытие условий (или покрытие предикатов) - каждое логическое подвыражение оценивается как истинное и ложное?

Например, рассмотрим следующую функцию C:

int foo (int x, int y)
{
    int z = 0;
    if ((x > 0) && (y > 0))
    {
        z = x;
    }
    return z;
}

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

  • Если во время этого выполнения функция 'foo' была вызвана хотя бы один раз, то покрытие этой функции удовлетворено.
  • Покрытие операторов для этой функции будет удовлетворено, если она была вызвана, например, as foo(1,1), как в этом случае, каждая строка в функции выполняется в том числе z = x;.
  • Вызывающие тесты foo(1,1)и foo(0,1)удовлетворяют охвату ветвления, потому что в первом случае оба ifусловия выполняются и z = x;выполняются, а во втором случае первое условие (x>0)не выполняется, что препятствует выполнению z = x;.
  • Покрытие условий может быть удовлетворено тестами, которые вызывают foo(1,0)и foo(0,1). Они необходимы, потому что в первом случае (x>0)оценивает true, а во втором - оценивает false. При этом первый корпус делает (y>0) false, а второй делает true.

Покрытие условий не обязательно подразумевает покрытие ветвей. Например, рассмотрим следующий фрагмент кода:

if a and b then

Покрытие условий может быть выполнено двумя тестами:

  • a=true, b=false
  • a=false, b=true

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

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

Измененное условие / покрытие решения

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

Покрытие условий / решений требует, чтобы выполнялось и решение, и покрытие условий. Однако для приложений, критичных к безопасности (например, для программного обеспечения авионики), часто требуется, чтобы удовлетворялось модифицированное покрытие условий / решений (MC / DC) . Этот критерий расширяет критерии условия / решения с требованиями, чтобы каждое условие независимо влияло на результат решения. Например, рассмотрим следующий код:

if (a or b) and c then

Критериям условия / решения будет соответствовать следующий набор тестов:

  • а = верно, б = верно, с = верно
  • а = ложь, б = ложь, с = ложь

Однако указанный выше набор тестов не будет удовлетворять модифицированному покрытию условий / решений, поскольку в первом тесте значение «b», а во втором тесте значение «c» не будет влиять на результат. Итак, для соответствия MC / DC необходим следующий набор тестов:

  • а = ложь, б = истина, с = ложь
  • а = ложь, б = истина , с = истина
  • а = ложь , б = ложь , с = истина
  • а = истина , б = ложь, с = истина

Покрытие множественных условий

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

  • а = ложь, б = ложь, с = ложь
  • а = ложь, б = ложь, с = истина
  • а = ложь, б = истина, с = ложь
  • а = ложь, б = истина, с = истина
  • a = истина, b = ложь, c = ложь
  • а = истина, б = ложь, с = истина
  • а = истина, б = истина, с = ложь
  • а = верно, б = верно, с = верно

Охват значения параметра

Охват значения параметра (PVC) требует, чтобы в методе, принимающем параметры, учитывались все общие значения для таких параметров. Идея состоит в том, что проверяются все общие возможные значения параметра. Например, общие значения для строки: 1) null, 2) пусто, 3) пробел (пробел, табуляция, новая строка), 4) допустимая строка, 5) недопустимая строка, 6) однобайтовая строка, 7) двухбайтовая строка. байтовая строка. Также может оказаться целесообразным использовать очень длинные строки. Отсутствие проверки каждого возможного значения параметра может привести к ошибке. Тестирование только одного из них может привести к 100% покрытию кода, поскольку покрывается каждая строка, но, поскольку тестируется только один из семи вариантов, ПВХ составляет только 14,2%.

Другие критерии покрытия

Есть и другие критерии покрытия, которые используются реже:

  • Покрытие Linear Code Sequence and Jump (LCSAJ), также известное как покрытие JJ-Path  - все ли LCSAJ / JJ-пути были выполнены?
  • Покрытие пути  - были ли выполнены все возможные маршруты через данную часть кода?
  • Покрытие входа / выхода  - были ли выполнены все возможные вызовы и возврат функции?
  • Покрытие цикла  - все возможные циклы выполнялись ноль раз, один раз и более одного раза?
  • Покрытие состояний  - было ли достигнуто и исследовано каждое состояние в конечном автомате ?
  • Охват потока данных.  Было ли достигнуто и изучено определение каждой переменной и ее использование?

Критически важные для безопасности или надежные приложения часто требуются для демонстрации 100% некоторой формы покрытия тестами. Например, стандарт ECSS -E-ST-40C требует 100% покрытия заявлений и решений для двух из четырех различных уровней критичности; для других значения целевого охвата являются предметом переговоров между поставщиком и заказчиком. Однако установка конкретных целевых значений - и, в частности, 100% - подвергалась критике со стороны практиков по разным причинам (см.) Мартин Фаулер пишет: «Я бы с подозрением отнесся к чему-то вроде 100% - это будет запахом того, что кто-то пишет тесты для сделайте счастливыми цифры охвата, но не думая о том, что они делают ».

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

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

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

На практике

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

При реализации политик тестового покрытия в среде разработки программного обеспечения необходимо учитывать следующее:

  • Каковы требования к покрытию для сертификации конечного продукта, и если да, то какой уровень покрытия требуется? Типичный уровень развития строгости следующий: утверждение, ветвь / решение, модифицированное условие / охват решения (MC / DC), LCSAJ ( линейная кодовая последовательность и переход ).
  • Будет ли покрытие измеряться по тестам, подтверждающим требования, предъявляемые к тестируемой системе ( DO-178B )?
  • Можно ли напрямую отследить созданный объектный код до операторов исходного кода? Некоторые сертификаты (например, DO-178B уровня A) требуют покрытия на уровне сборки, если это не так: «Затем необходимо выполнить дополнительную проверку объектного кода, чтобы установить правильность таких сгенерированных кодовых последовательностей» ( DO-178B ) пункт 6.4.4.2.

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

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

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

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

Использование в промышленности

Покрытие испытаний является одним из факторов, учитываемых при сертификации оборудования авионики по безопасности. Руководящие принципы, по которым авиационное оборудование сертифицировано Федеральным авиационным управлением (FAA), задокументированы в DO-178B и DO-178C .

Покрытие испытаний также является требованием части 6 стандарта автомобильной безопасности ISO 26262 « Транспортные средства - Функциональная безопасность» .

Смотрите также

использованная литература