В программной инженерии покрытие кода , также называемое тестовым покрытием , представляет собой процентную меру степени выполнения исходного кода программы при запуске определенного тестового набора . Программа с высоким покрытием кода имеет большую часть своего исходного кода, выполняемого во время тестирования, что предполагает, что у нее меньше шансов содержать необнаруженные программные ошибки по сравнению с программой с низким покрытием кода. [1] [2] Для расчета тестового покрытия можно использовать множество различных метрик. Некоторые из самых основных — это процент подпрограмм программы и процент операторов программы, вызываемых во время выполнения тестового набора.
Покрытие кода было одним из первых методов, изобретенных для систематического тестирования программного обеспечения . Первая опубликованная ссылка была Миллером и Мэлони в Communications of the ACM в 1963 году. [3]
Чтобы измерить, какой процент кода был выполнен тестовым набором , используются один или несколько критериев покрытия . Они обычно определяются как правила или требования, которым тестовый набор должен удовлетворять. [4]
Существует ряд критериев покрытия, но основными из них являются: [5]
Например, рассмотрим следующую функцию C :
int foo ( int x , int y ) { int z = 0 ; если (( x > 0 ) && ( y > 0 )) { z = x ; } вернуть z ; }
Предположим, что эта функция является частью какой-то более крупной программы, и эта программа была запущена с помощью некоторого набора тестов.
foo
была вызвана хотя бы один раз.foo(1,1)
, поскольку в этом случае будет выполнена каждая строка в функции, включая z = x;
.foo(1,1)
и , foo(0,1)
поскольку в первом случае оба if
условия выполняются и z = x;
выполняется, тогда как во втором случае первое условие, (x>0)
, не выполняется, что препятствует выполнению z = x;
.foo(1,0)
, foo(0,1)
и foo(1,1)
. Они необходимы, поскольку в первом случае (x>0)
вычисляется как true
, а во втором — как false
. В то же время, первый случай делает (y>0)
false
, второй случай не вычисляет (y>0)
(из-за ленивой оценки булевого оператора), третий случай делает его true
.В языках программирования, которые не выполняют оценку короткого замыкания , покрытие условий не обязательно подразумевает покрытие ветвей. Например, рассмотрим следующий фрагмент кода Pascal :
если а и б то
Условие покрытия может быть удовлетворено двумя тестами:
a=true
,b=false
a=false
,b=true
Однако этот набор тестов не удовлетворяет условию покрытия ветвей, поскольку ни один из случаев не будет соответствовать if
условию.
Внесение ошибок может потребоваться для обеспечения адекватного покрытия всех условий и ветвей кода обработки исключений во время тестирования.
Комбинацию покрытия функций и покрытия ветвей иногда также называют покрытием решений . Этот критерий требует, чтобы каждая точка входа и выхода в программе была вызвана по крайней мере один раз, и каждое решение в программе приняло все возможные результаты по крайней мере один раз. В этом контексте решение представляет собой логическое выражение, включающее условия и ноль или более логических операторов. Это определение не то же самое, что покрытие ветвей, [6] однако термин покрытие решений иногда используется как его синоним. [7]
Покрытие условий/решений требует, чтобы были удовлетворены как решение, так и покрытие условий. Однако для критически важных для безопасности приложений (таких как программное обеспечение авионики ) часто требуется, чтобы было удовлетворено модифицированное покрытие условий/решений (MC/DC) . Этот критерий расширяет критерии условий/решений требованиями, чтобы каждое условие влияло на результат решения независимо.
Например, рассмотрим следующий код:
если ( а или б ) и в , то
Критерии условия/решения будут удовлетворены с помощью следующего набора тестов:
Однако вышеуказанный набор тестов не будет удовлетворять модифицированному покрытию условий/решений, поскольку в первом тесте значение 'b', а во втором тесте значение 'c' не повлияет на выход. Таким образом, для удовлетворения MC/DC необходим следующий набор тестов:
Этот критерий требует, чтобы все комбинации условий внутри каждого решения были проверены. Например, фрагмент кода из предыдущего раздела потребует восемь тестов:
Покрытие значений параметров (PVC) требует, чтобы в методе, принимающем параметры, рассматривались все общие значения для таких параметров. Идея заключается в том, что проверяются все общие возможные значения для параметра. [8] Например, общие значения для строки: 1) null , 2) пусто, 3) пробел (пробел, табуляция, новая строка), 4) допустимая строка, 5) недопустимая строка, 6) однобайтовая строка, 7) двухбайтовая строка. Также может быть целесообразно использовать очень длинные строки. Неспособность проверить каждое возможное значение параметра может привести к ошибке. Тестирование только одного из них может привести к 100% покрытию кода, поскольку покрывается каждая строка, но поскольку проверяется только один из семи вариантов, PVC составляет всего 14,2%.
Существуют и другие критерии покрытия, которые используются реже:
Критически важные для безопасности или надежные приложения часто должны демонстрировать 100% покрытия какой-либо формы тестирования. Например, стандарт ECSS -E-ST-40C требует 100% покрытия утверждений и решений для двух из четырех различных уровней критичности; для других целевые значения покрытия являются предметом переговоров между поставщиком и заказчиком. [11] Однако установление конкретных целевых значений - и, в частности, 100% - подвергалось критике со стороны практиков по разным причинам (ср. [12] ). Мартин Фаулер пишет: «Я бы с подозрением отнесся к чему-либо вроде 100% - это было бы похоже на то, что кто-то пишет тесты, чтобы порадовать цифры покрытия, но не думает о том, что он делает». [13]
Некоторые из критериев покрытия выше связаны. Например, покрытие пути подразумевает покрытие решения, утверждения и входа/выхода. Покрытие решения подразумевает покрытие утверждения, поскольку каждое утверждение является частью ветви.
Полное покрытие путей, описанного выше типа, обычно непрактично или невозможно. Любой модуль с последовательностью решений в нем может иметь до путей внутри себя; конструкции циклов могут привести к бесконечному числу путей. Многие пути также могут быть невыполнимыми, поскольку в тестируемой программе нет входных данных, которые могли бы вызвать выполнение этого конкретного пути. Однако было доказано, что универсальный алгоритм для определения невыполнимых путей невозможен (такой алгоритм может быть использован для решения проблемы остановки ). [14] Тестирование базисного пути , например, является методом достижения полного покрытия ветвей без достижения полного покрытия путей. [15]
Методы практического тестирования покрытия путей вместо этого пытаются идентифицировать классы путей кода, которые отличаются только количеством выполнений цикла, и для достижения покрытия «базового пути» тестер должен охватить все классы путей. [ требуется цитата ] [ требуется пояснение ]
Целевое программное обеспечение создается со специальными опциями или библиотеками и запускается в контролируемой среде для сопоставления каждой выполняемой функции с функциональными точками в исходном коде. Это позволяет тестировать части целевого программного обеспечения, которые редко или никогда не используются в обычных условиях, и помогает убедиться, что наиболее важные условия (функциональные точки) были протестированы. Затем полученный вывод анализируется, чтобы увидеть, какие области кода не были выполнены, и тесты обновляются, чтобы включать эти области по мере необходимости. В сочетании с другими методами тестового покрытия цель состоит в разработке строгого, но управляемого набора регрессионных тестов.
При реализации политик тестового покрытия в среде разработки программного обеспечения необходимо учитывать следующее:
Авторы программного обеспечения могут просматривать результаты тестового покрытия, чтобы разрабатывать дополнительные тесты и наборы входных данных или конфигураций для увеличения покрытия жизненно важных функций. Две распространенные формы тестового покрытия — это покрытие операторов (или строк) и покрытие ветвей (или ребер). Покрытие линий сообщает о следе выполнения тестирования с точки зрения того, какие строки кода были выполнены для завершения теста. Покрытие ребер сообщает, какие ветви или точки принятия решений в коде были выполнены для завершения теста. Они оба сообщают метрику покрытия, измеряемую в процентах. Значение этого зависит от того, какая форма(ы) покрытия была использована, так как 67% покрытие ветвей является более полным, чем 67% покрытие операторов.
Обычно инструменты тестового покрытия требуют вычислений и регистрации в дополнение к фактической программе, тем самым замедляя приложение, поэтому обычно этот анализ не выполняется в производстве. Как и следовало ожидать, существуют классы программного обеспечения, которые не могут быть подвергнуты этим тестам покрытия, хотя степень отображения покрытия может быть приблизительно оценена посредством анализа, а не прямого тестирования.
Также существуют некоторые виды дефектов, на которые влияют такие инструменты. В частности, некоторые состояния гонки или аналогичные операции, чувствительные к реальному времени , могут быть замаскированы при запуске в тестовых средах; хотя, наоборот, некоторые из этих дефектов может быть легче обнаружить в результате дополнительных накладных расходов на тестовый код.
Большинство профессиональных разработчиков программного обеспечения используют покрытие C1 и C2. C1 обозначает покрытие операторов, а C2 — покрытие ветвей или условий. При сочетании C1 и C2 можно покрыть большинство операторов в кодовой базе. Покрытие операторов также будет охватывать покрытие функций с входом и выходом, циклом, путем, потоком состояний, потоком управления и потоком данных. С помощью этих методов можно достичь почти 100% покрытия кода в большинстве программных проектов. [17]
Охват испытаний является одним из соображений при сертификации безопасности авионики. Руководящие принципы, по которым авионика сертифицируется Федеральным управлением гражданской авиации (FAA), задокументированы в DO-178B [16] и DO-178C . [18]
Охват испытаниями также является требованием части 6 стандарта безопасности автомобилей ISO 26262 «Дорожные транспортные средства. Функциональная безопасность» . [19]