теория_6 (Методичка и инструкции на ЛР №8)
Описание файла
Файл "теория_6" внутри архива находится в следующих папках: Методичка и инструкции на ЛР №8, Инструкции, Задание_6. Документ из архива "Методичка и инструкции на ЛР №8", который расположен в категории "". Всё это находится в предмете "технологии разработки программного обеспечения (по)" из 10 семестр (2 семестр магистратуры), которые можно найти в файловом архиве МГТУ им. Н.Э.Баумана. Не смотря на прямую связь этого архива с МГТУ им. Н.Э.Баумана, его также можно найти и в других разделах. Архив можно найти в разделе "лабораторные работы", в предмете "технологии разработки по" в общих файлах.
Онлайн просмотр документа "теория_6"
Текст из документа "теория_6"
19.2. Понятие покрытия
19.2.1. Покрытие программного кода
На этом семинаре познакомимся с одной из оценок качества системы тестов — с ее полнотой, т.е. величиной той части функциональности системы, которая проверяется тестовыми примерами. Полная система тестов позволяет утверждать, что система реализует всю функциональность, указанную в требованиях, и, что еще более важно – не реализует никакой другой функциональности. Степень покрытия программного кода тестами – важный количественный показатель, позволяющий оценить качество системы тестов, а в некоторых случаях – и качество тестируемой программной системы.
Одним из наиболее часто используемых методов определения полноты системы тестов является определение отношения количества тест-требований, для которых существуют тестовые примеры, к общему количеству тест-требований, — т.е. в данном случае речь идет о покрытии тестовыми примерами тест-требований. В качестве единицы измерения степени покрытия здесь выступает процент тест-требований, для которых существуют тестовые примеры, называемый процентом покрытых тест-требований. Покрытие требований позволяет оценить степень полноты системы тестов по отношению к функциональности системы, но не позволяет оценить полноту по отношению к ее программной реализации. Одна и та же функция может быть реализована при помощи совершенно различных алгоритмов, требующих разного подхода к организации тестирования.
Для более детальной оценки полноты системы тестов при тестировании стеклянного ящика анализируется покрытие программного кода, называемое также структурным покрытием.
Во время работы каждого тестового примера выполняется некоторый участок программного кода системы, при выполнении всей системы тестов выполняются все участки программного кода, которые задействует эта система тестов. В случае, если существуют участки программного кода, не выполненные при выполнении системы тестов, система тестов потенциально неполна (т.е. не проверяет всю функциональность системы), либо система содержит участки защитного кода или неиспользуемый код (например, "закладки" или задел на будущее использование системы). Таким образом, отсутствие покрытия каких-либо участков кода является сигналом к переработке тестов или кода (а иногда – и требований).
К анализу покрытия программного кода можно приступать только после полного покрытия требований. Полное покрытие программного кода не гарантирует того, что тесты проверяют все требования к системе. Одна из типичных ошибок начинающего тестировщика – начинать с покрытия кода, забывая про покрытие требований.
Замечание. Необходимо помнить, что разработка тестовых примеров, обеспечивающих полное покрытие тестируемого программного кода, относится к структурному тестированию кода. Перед началом структурного тестирования должно быть полностью закончено функциональное тестирование кода как черного ящика (чем мы и занимались на предыдущих семинарах). Только после этого можно переходить к улучшению покрытия. В идеальном случае при полном покрытии функциональных требований должно получаться 100% покрытие кода. Однако на практике такое происходит только в случае очень простого кода. Причина недопокрытия кода при полном покрытии требований – либо неполнота требований, либо недостаточно полный анализ требований тестировщиком. В первом случае обычно требуется доработка требований, во втором – тест-требований и тест-плана.
19.2.2. Уровни покрытия
19.2.2.1. По строкам программного кода (Statement Coverage)
Для обеспечения полного покрытия программного кода на данном уровне необходимо, чтобы в результате выполнения тестов каждый оператор был выполнен хотя бы один раз. Перед началом тестирования необходимо выделить переменные, от которых зависит выполнение различных ветвей условий и циклов в коде – управляющие входные переменные. Изменение значений этих переменных будет влиять на то, какие строки кода будут выполняться в различных тестовых примерах.
Пример. В следующем фрагменте кода входными переменными являются prev и ShowMessage.
if (prev == "оператор" || prev == "унарный оператор")
{
if (ShowMessage)
{
MessageBox.Show("Два подряд оператора на
" + i.ToString() + " символе.");
}
else
{
Log.Write("Два подряд оператора на " +
+ i.ToString() + " символе.")
}
Program.res = 4;
return "&Error 04 at " +
+ i.ToString();
}
Для того, чтобы полностью покрыть данный код по строкам, т.е. выполнить все строки кода, достаточно двух тестовых примеров:
1 | 2 | |
prev | оператор | оператор |
ShowMessage | true | false |
В первом тестовом примере осуществляется вход в первый условный оператор if, затем в первую ветвь второго оператора if. Второй тестовый пример осуществляет аналогичные действия, но для второй ветви второго оператора if. В результате все строки кода оказываются выполненными. Легко увидеть, что, несмотря на полное покрытие по строкам, этот набор тестовых примеров не проверяет всей функциональности (даже не видя требований, логично предположить, что в них должно описываться поведение системы и для значения переменной prev = "оператор", и для значения prev = "унарный оператор").
Также проблемы этого метода покрытия можно увидеть и на примерах других управляющих структур. Например, проблемы возникают при проверке циклов do … while – при данном уровне покрытия достаточно выполнение цикла только один раз, при этом метод совершенно нечувствителен к логическим операторам || и &&.
Другой особенностью данного метода является зависимость уровня покрытия от структуры программного кода. На практике часто не требуется 100% покрытия программного кода, вместо этого устанавливается допустимый уровень покрытия, например 75%. Проблемы могут возникнуть при покрытии следующего фрагмента программного кода:
if (condition)
MethodA();
else
MethodB();
Если MethodA() содержит 99 операторов, а MethodB() — один оператор, то единственного тестового примера, устанавливающего condition в true, будет достаточно для достижения необходимого уровня покрытия. При этом аналогичный тестовый пример, устанавливающий значение condition в false, даст слишком низкий уровень покрытия.
19.2.2.2. По веткам условных операторов (Decision Coverage)
Для обеспечения полного покрытия по данному методу каждая точка входа и выхода в программе и во всех ее функциях должна быть выполнена по крайней мере один раз и все логические выражения в программе должны принять каждое из возможных значений хотя бы один раз; таким образом, для покрытия по веткам требуется как минимум два тестовых примера.
Также данный метод называют: branch coverage, all-edges coverage, basis path coverage, DC, C2, decision-decision-path.
В отличие от предыдущего уровня покрытия данный метод учитывает покрытие условных операторов с пустыми ветками.
Пример. Для покрытия предыдущего примера кода по ветвям потребуется уже три тестовых примера. Это связано с тем, что первый условный оператор if имеет неявную ветвь – пустую ветвь else. Для обеспечения покрытия по ветвям необходимо покрывать и пустые ветви.
1 | 2 | 3 | |
prev | оператор | оператор | операнд |
ShowMessage | true | false | true |
Первые два тестовых примера аналогичны предыдущему случаю, третий предназначен для покрытия неявной ветви. При этом надо заметить, что значение переменной ShowMessage не играет никакой роли для покрытия – участок кода, использующий эту переменную, просто не выполняется.
Особенность данного уровня покрытия заключается в том, что на нем не учитываются логические выражения, значения компонент которых получаются вызовом методов. Например, на следующем фрагменте программного кода
if (condition1 && (condition2 || Method()))
statement1;
else
statement2;
полное покрытие по веткам может быть достигнуто при помощи двух тестовых примеров:
1 | 2 | |
condition1 | true | false |
condition2 | true | true/false |
В обоих случаях не происходит вызова метода Method(), хотя покрытие данного участка кода будет полным. Для проверки вызова метода Method() необходимо добавить еще один тестовый пример (который, однако, не улучшает степени покрытия по веткам):
1 | 2 | 3 | |
condition1 | true | false | true |
condition2 | true | true/false | false |
19.2.2.3. По компонентам логических условий
Для более полного анализа компонент условий в логических операторах существует несколько методов, учитывающих структуру компонент условий и значения, которые они принимают при выполнении тестовых примеров.
19.2.2.4. Покрытие по условиям (Condition Coverage)
Для обеспечения полного покрытия по данному методу каждая компонента логического условия в результате выполнения тестовых примеров должна принимать все возможные значения, но при этом не требуется, чтобы само логическое условие принимало все возможные значения. Так, например, при тестировании следующего фрагмента
if (condition1 || condition2)
MethodA();
else
MethodB();
для покрытия по условиям потребуется два тестовых примера:
1 | 2 | |
condition1 | true | False |
condition2 | false | True |
При этом значение логического условия будет принимать значение только true; таким образом, при полном покрытии по условиям не будет достигаться покрытие по веткам.
19.2.2.5. Покрытие по веткам/условиям (Condition/Decision Coverage)
Данный метод сочетает требования предыдущих двух методов – для обеспечения полного покрытия необходимо, чтобы как логическое условие, так и каждая его компонента приняла все возможные значения.
Для покрытия рассмотренного выше фрагмента с условием
(condition1 || condition2)
потребуется 2 тестовых примера:
1 | 2 | |
condition1 | true | false |
condition2 | true | false |
Однако, эти два тестовых примера не позволят протестировать правильность логической функции – вместо OR в программном коде могла быть ошибочно записана операция AND.
19.2.2.6. Покрытие по всем условиям (Multiple Condition Coverage)
Для выявления неверно заданных логических функций был предложен метод покрытия по всем условиям. При данном методе покрытия должны быть проверены все возможные наборы значений компонент логических условий. Т.е. в случае n компонент потребуется 2n тестовых примеров, каждый из которых проверяет один набор значений, Тесты, необходимые для полного покрытия по данному методу, дают полную таблицу истинности для логического выражения.
Несмотря на очевидную полноту системы тестов, обеспечивающей этот уровень покрытия, данный метод редко применяется на практике в связи с его сложностью и избыточностью.
Еще одним недостатком метода является зависимость количества тестовых примеров от структуры логического выражения. Так, для условий, содержащих одинаковое количество компонент и логических операций:
a && b && (c || (d && e))
((a || b) && (c || d)) && e
потребуется разное количество тестовых примеров. Для первого случая для полного покрытия нужно 6 тестов, для второго – 11.
19.2.2.7. Метод MC/DC для уменьшения количества тестовых примеров при 3-м уровне покрытия кода
Для уменьшения количества тестовых примеров при тестировании логических условий фирмой Boeing был разработан модифицированный метод покрытия по веткам/условиям (Modified Condition/Decision Coverage или MC/DC). Данный метод широко используется при верификации бортового авиационного программного обеспечения согласно процессам стандарта DO-178B.