Национальный исследовательский ядерный университет «МИФИ»
Опубликован: 28.11.2007 | Доступ: свободный | Студентов: 5123 / 786 | Оценка: 4.53 / 3.65 | Длительность: 22:18:00
ISBN: 978-5-94774-825-3
Специальности: Программист, Тестировщик
Лекция 4:

Тестирование программного кода (покрытия)

6.3. Покрытие программного кода

6.3.1. Понятие покрытия

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

Один из часто используемых методов определения полноты системы тестов является определение отношения количества тест-требований, для которых существуют тестовые примеры, к общему количеству тест-требований. Т.е. в данном случае речь идет о покрытии тестовыми примерами тест-требований. В качестве единицы измерения степени покрытия здесь выступает процент тест-требований, для которых существуют тестовые примеры, называемый процентом покрытых тест-требований.

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

Для более детальной оценки полноты системы тестов при тестировании стеклянного ящика анализируется покрытие программного кода, называемое также структурным покрытием.

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

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

6.3.2. Уровни покрытия

6.3.3. По строкам программного кода (Statement Coverage)

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

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

Например, для полного покрытия всех строк следующего участка программного кода на языке C достаточно одного тестового примера:

Вход: condition = true; Ожидаемый выход: *p = 123.
int* p = NULL;
if (condition)
    p = &variable;
*p = 123;

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

Аналогичные проблемы возникают при проверке циклов do … while - при данном уровне покрытия достаточно выполнение цикла только один раз, при этом метод совершенно нечувствителен к логическим операторам || и &&

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

if (condition)
   functionA();
else
   functionB();

Если functionA() содержит 99 операторов, а functionB() - один оператор, то единственного тестового примера, устанавливающего condition в true, будет достаточно для достижения необходимого уровня покрытия. При этом аналогичный тестовый пример, устанавливающий значение condition в false, даст слишком низкий уровень покрытия.

6.3.3.1. По веткам условных операторов (Decision Coverage)

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

Также данный метод называют: branch coverage, all-edges coverage, basis path coverage, DC, C2, decision-decision-path.

В отличие от предыдущего уровня покрытия данный метод учитывает покрытие условных операторов с пустыми ветками. Так, для покрытия по веткам участка программного кода

a = 0;
if (condition) {
  a = 1;
}

необходимы два тестовых примера:

1. Вход: condition = true; Ожидаемый выход: a = 1;
2. Вход: condition = false; Ожидаемый выход: a = 0;

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

if ( condition1 && ( condition2 || function1() ) )
    statement1;
else
    statement2;

полное покрытие по веткам может быть достигнуто при помощи двух тестовых примеров:

1. Вход: condition1 = true, condition2 = true
2. Вход: condition1 = false, condition2 = true/false (любое значение)

В обоих случаях не происходит вызова функции function1(), хотя покрытие данного участка кода будет полным. Для проверки вызова функции function1() необходимо добавить еще один тестовый пример (который, однако, не улучшает степени покрытия по веткам):

3. Вход: condition1 = true, condition2 = false.
6.3.3.2. По компонентам логических условий

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

6.3.3.3. Покрытие по условиям (Condition Coverage)

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

if (condition1 | condition2)
  functionA();
else
  functionB();

для покрытия по условиям потребуется два тестовых примера:

(1)  Вход: condition1 = true, condition2 = false
(2)  Вход: condition1 = false, condition2 = true.

При этом значение логического условия будет принимать значение только true, таким образом, при полном покрытии по условиям не будет достигаться покрытие по веткам.

6.3.3.4. Покрытие по веткам/условиям (Condition/Decision Coverage)

Данный метод сочетает требования предыдущих двух методов - для обеспечения полного покрытия необходимо, чтобы как логическое условие, так и каждая его компонента приняла все возможные значения.

Для покрытия рассмотренного выше фрагмента с условием condition1 | condition2 потребуется 2 тестовых примера:

1.  Вход: condition1 = true, condition2 = true
2.  Вход: condition1 = false, condition2 = false.

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

6.3.3.5. Покрытие по всем условиям (Multiple Condition Coverage)

Для выявления неверно заданных логических функций был предложен метод покрытия по всем условиям. При данном методе покрытия должны быть проверены все возможные наборы значений компонент логических условий. Т.е. в случае n компонент потребуется 2n тестовых примеров, каждый из которых проверяет один набор значений, Тесты, необходимые для полного покрытия по данному методу, дают полную таблицу истинности для логического выражения.

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

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

a && b && (c || (d && e))
((a || b) && (c || d)) && e

потребуется разное количество тестовых примеров. Для первого случая для полного покрытия нужно 6 тестов, для второго - 11.

Илья Макаренко
Илья Макаренко

Добрый день.

Вопрос №1

Какова стоимость получения диплома о мини-МБА по данному курсу? Или ориентироваться на указанную на сайте?

Вопрос №2

Возможно ли начать обучение без потери результатов, не отправив документы на зачисление, а отправку выполнить позже?

Александр Медов
Александр Медов

Здравствуйте, какова полная сумма предоставленной услуги с печатью документа и отправкой по почте?