Тестовые примеры, рассматриваемые в предыдущих разделах, не существуют сами по себе - каждый тестовый пример проверяет одну ситуацию в работе системы, но вся совокупность тестовых примеров должна полностью проверять всю функциональность системы. В связи с этим описания тестовых примеров объединяют в документы, называемыми тест-планами.
Тест-план представляет собой документ, в котором перечислены либо все тестовые примеры, необходимые для тестирования системы, либо часть тестовых примеров, объединенных по определенному признаку.
Тест-план может быть написан на естественном или формальном языке; в последнем случае возможна передача тест-плана на вход тестового окружения для автоматического выполнения определенных в тест-плане тестовых примеров.
Существует несколько причин для объединения описаний тестовых примеров в единый документ или несколько документов.
Поскольку тестовые примеры пишутся на основании функциональных или тест-требований, при тестировании необходимо удостовериться, что для каждого требования существует хотя бы один тестовый пример. Это достигается введением единой схемы идентификации тестовых примеров (например - сквозной нумерации) и введением ссылок на требования, на основе которых тестовый пример написан.
Тестовые примеры, предназначенные для проверки одних и тех же модулей системы, рационально объединять в смысловые группы. Причина в том, что у таких примеров, как правило, очень похожи входные данные и сценарии, а группировка позволяет выявлять опечатки и ошибки в тестах.
При изменении тестируемой системы в ходе ее жизненного цикла неизбежно приходится изменять тестовые примеры. Общие обзоры тест-требований и тест-планов позволяют выявить, какие тесты должны быть изменены или удалены, а в каких смысловых группах необходимо создание новых тестовых примеров, проверяющих новую функциональность.
Одно из важных свойств тестового примера - его независимость. Это означает, что результат выполнения тестового примера не должен изменяться в зависимости от того, какие тесты выполнялись до него. Как правило, независимость тестовых примеров достигается полной реинициализацией тестового окружения перед выполнением каждого нового тестового примера. Однако, часто возникают ситуации, в которых, для экономии времени выполнения, тесты объединяются в последовательности, где каждый следующий тестовый пример использует состояние тестового окружения или тестируемой системы, достигнутое во время предыдущего теста. Такие связанные тестовые примеры должны быть отдельно помечены для того, чтобы сохранить корректный порядок их следования.
Рассмотрим типовую структуру тест-плана, написанного на естественном языке и содержащего тестовые примеры для проверки работы модуля расчета контрольных сумм.
Каждый тестовый пример в этом тест-плане имеет уникальный номер и ссылку на тест-требование, на основе которого он написан.
Общее описание теста помогает при сопровождении тест-планов - внесении изменений при изменении системы, инспекциях тест-планов, выявляющих несогласованность и т.п.
Также в каждом тестовом примере обязательно перечислены все входные значения и ожидаемые выходные значения, а также сценарий, описывающий последовательность действий, которые необходимо выполнить тестовому окружению для выполнения тестового примера.
Тестовый пример 1 Номер тест-требования: 2а, 2b Описание теста: В данном тесте проверяется правильность вычисления значения контрольной суммы (поля CRC) при непустом значении поля CRC и нулевых значениях элементов записи. Входные данные: CRC = 12345, A=0, B=0, C=0, D=0 Ожидаемые выходные данные: CRC = 0, A=0, B=0, C=0, D=0, Empty = TRUE Сценарий теста: 1. Установка значения поля CRC в 12345 2. Установка значений полей A-F в 0 3. Вызов функции Set_CRC 4. Проверка значений CRC на 0 и Empty на TRUE
Тестовый пример 2 Номер тест-требования: 2a Описание теста: В данном тесте проверяется соответствие алгоритма вычисления поля CRC, заданному в спецификации требований. Входные данные: CRC = 0, A-D заполнены байтами 01010101b Ожидаемые выходные данные: CRC = 0111100b, Empty = FALSE Сценарий теста: 1. Установка значения поля CRC в 0 2. Заполнение байт полей A-D байтами 01010101b 3. Вызов функции Set_CRC 4. Проверка значений CRC на 0111100b и Empty на FALSE
Тестовый пример 3 Номер тест-требования: 2a Описание теста: В данном тесте проверяется неизменность полей A-F записи при вычислении поля CRC (подсчете контрольной суммы). Входные данные: CRC = 0, A-D заполнены байтами 01010101b Ожидаемые выходные данные: A-D заполнены байтами 01010101b, Сценарий теста: 1. Установка значения поля CRC в 0 2. Заполнение байт полей A-D байтами 01010101b 3. Вызов функции Set_CRC 4. Проверка значений байт полей A-D на 01010101b
Такая структура тест-плана позволяет описывать тестовые примеры с совершенно различными наборами входных и выходных данных и сценариями, однако при большом количестве тестовых примеров эта схема станет слишком громоздкой. Позднее будут рассмотрены табличные формы представления тест-планов, позволяющие записывать их более компактно.
В результате выполнения каждого тестового примера тестовое окружение сравнивает ожидаемые и реальные выходные значения. В случае, если эти значения совпадают, тест считается пройденным, т.к. система выдала именно те выходные значения, которые ожидались; в противном случае тест считается не пройденным.
Каждый непройденный тест потенциально указывает на потенциальный дефект в тестируемой системе, а общее их количество позволяет оценивать качество тестируемого программного кода и объем изменений, которые необходимо в него внести для устранения дефектов.
Для построения такой интегральной оценки после выполнения всех тестовых примеров тестовым окружением собирается статистика выполнения, которая, как правило, записывается в файл отчета о выполнении тестов. Существует несколько степеней подробности статистики выполнения тестов:
Например,
180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed Invoking test case 2 … Failed Invoking test case 3 … Failed <…> Invoking test case 200 … Passed Final stats: 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 B = 450 B = 0 Message = "Submenu 1" Message = "" --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 B = 0 B = 300 Message = "" Message = "Main Menu" --- <…> Invoking test case 200 … Passed --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 FAIL B = 450 B = 0 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "Submenu 1" Message = "" FAIL --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 FAIL B = 0 B = 300 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "Main Menu" FAIL --- <…> Invoking test case 200 … Passed --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed A = 0 A = 0 P B = 0 B = 0 P C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "" P --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 FAIL B = 450 B = 0 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "Submenu 1" Message = "" FAIL --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 FAIL B = 0 B = 300 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "Main Menu" FAIL --- <…> Invoking test case 200 … Passed Message = "Submenu 1" Message = "Submenu 1 P Prompt = ">" Prompt = ">" P --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Более детально различные форматы отчетов о тестировании будут рассмотрены позднее, а пока остановимся более подробно на важном критерии оценки качества системы тестов и степени полноты тестирования системы - уровне покрытия программного кода тестами.
Одна из оценок качества системы тестов - это ее полнота, т.е. величина той части функциональности системы, которая проверяется тестовыми примерами. Обычно за меру полноты берут отношение объема проверенной части системы к ее объему в целом. Полная система тестов позволяет утверждать, что система реализует всю функциональность, указанную в требованиях, и, что еще более важно, - не реализует никакой другой функциональности.
Один из часто используемых методов определения полноты системы тестов является определение отношения количества тест-требований, для которых существуют тестовые примеры, к общему количеству тест-требований. Т.е. в данном случае речь идет о покрытии тестовыми примерами тест-требований. В качестве единицы измерения степени покрытия здесь выступает процент тест-требований, для которых существуют тестовые примеры, называемый процентом покрытых тест-требований.
Покрытие требований позволяет оценить степень полноты системы тестов по отношению к функциональности системы, но не позволяет оценить полноту по отношению к ее программной реализации. Одна и та же функция может быть реализована при помощи совершенно различных алгоритмов, требующих разного подхода к организации тестирования.
Для более детальной оценки полноты системы тестов при тестировании стеклянного ящика анализируется покрытие программного кода, называемое также структурным покрытием.
Во время работы каждого тестового примера выполняется некоторый участок программного кода системы; при выполнении всей системы тестов выполняются все участки программного кода, которые задействует эта система тестов. В случае, если существуют участки программного кода, не выполненные при выполнении системы тестов, система тестов потенциально неполна (т.е. не проверяет всю функциональность системы), либо система содержит участки защитного кода или неиспользуемый код (например, "закладки" или задел на будущее использование системы). Таким образом, отсутствие покрытия каких-либо участков кода является сигналом к переработке тестов или кода (а иногда - и требований).
К анализу покрытия программного кода можно приступать только после полного покрытия требований. Полное покрытие программного кода не гарантирует того, что тесты проверяют все требования к системе. Одна из типичных ошибок начинающего тестировщика - начинать с покрытия кода, забывая про покрытие требований.
Для обеспечения полного покрытия программного кода на данном уровне необходимо, чтобы в результате выполнения тестов каждый оператор был выполнен хотя бы один раз.
Особенность данного уровня покрытия состоит в том, что на нем затруднен анализ покрытия некоторых управляющих структур.
Например, для полного покрытия всех строк следующего участка программного кода на языке 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, даст слишком низкий уровень покрытия.
Для обеспечения полного покрытия по данному методу каждая точка входа и выхода в программе и во всех ее функциях должна быть выполнена по крайней мере один раз, и все логические выражения в программе должны принять каждое из возможных значений хотя бы один раз, - таким образом, для покрытия по веткам требуется как минимум два тестовых примера.
Также данный метод называют: .
В отличие от предыдущего уровня покрытия данный метод учитывает покрытие условных операторов с пустыми ветками. Так, для покрытия по веткам участка программного кода
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.
Для более полного анализа компонент условий в логических операторах существует несколько методов, учитывающих структуру компонент условий и значения, которые они принимают при выполнении тестовых примеров.
Для обеспечения полного покрытия по данному методу каждая компонента логического условия в результате выполнения тестовых примеров должна принимать все возможные значения, но при этом не требуется, чтобы само логическое условие принимало все возможные значения. Так, например, при тестировании следующего фрагмента:
if (condition1 | condition2) functionA(); else functionB();
для покрытия по условиям потребуется два тестовых примера:
(1) Вход: condition1 = true, condition2 = false (2) Вход: condition1 = false, condition2 = true.
При этом значение логического условия будет принимать значение только true, таким образом, при полном покрытии по условиям не будет достигаться покрытие по веткам.
Данный метод сочетает требования предыдущих двух методов - для обеспечения полного покрытия необходимо, чтобы как логическое условие, так и каждая его компонента приняла все возможные значения.
Для покрытия рассмотренного выше фрагмента с условием condition1 | condition2 потребуется 2 тестовых примера:
1. Вход: condition1 = true, condition2 = true 2. Вход: condition1 = false, condition2 = false.
Однако, эти два тестовых примера не позволят протестировать правильность логической функции - вместо OR в программном коде могла быть ошибочно записана операция AND.
Для выявления неверно заданных логических функций был предложен метод покрытия по всем условиям. При данном методе покрытия должны быть проверены все возможные наборы значений компонент логических условий. Т.е. в случае n компонент потребуется 2n тестовых примеров, каждый из которых проверяет один набор значений, Тесты, необходимые для полного покрытия по данному методу, дают полную таблицу истинности для логического выражения.
Несмотря на очевидную полноту системы тестов, обеспечивающей этот уровень покрытия, данный метод редко применяется на практике в связи с его сложностью и избыточностью.
Еще одним недостатком метода является зависимость количества тестовых примеров от структуры логического выражения. Так, для условий, содержащих одинаковое количество компонент и логических операций:
a b (c || (d e)) ((a || b) (c || d)) e
потребуется разное количество тестовых примеров. Для первого случая для полного покрытия нужно 6 тестов, для второго - 11.
Для уменьшения количества тестовых примеров при тестировании логических условий фирмой Boeing был разработан модифицированный метод покрытия по веткам/условиям (Modified Condition/
Для обеспечения полного покрытия по этому методу необходимо выполнение следующих условий:
Покрытие по этой метрике требует достаточно большого количества тестов для того, чтобы проверить каждое условие, которое может повлиять на результат выражения, однако это количество значительно меньше, чем требуемое для метода покрытия по всем условиям. В таблице 6.1 приведены примеры тестовых наборов, необходимых для тестирования логических блоков по MC/DC. Так, например, для блока OR достаточно n+1 тестовых примеров, где n - количество входов логического блока. Первый тестовый пример показывает, что при нулевых значениях входов значение выхода также нулевое. В каждом из следующих n примеров значение каждого входа устанавливается в 1, чем показывается независимое влияние входов на значение выхода.
| AND блок. Реализует логическую функцию | |||||||||||||
| № набора | 1 | 2 | 3 | 4 | ··· | n + 1 | № набора | 1 | 2 | 3 | 4 | ··· | n + 1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Вход 1 | T | F | T | T | ··· | T | Вход 1 | T | F | T | T | ··· | T |
| Вход 2 | T | T | F | T | ··· | T | Вход 2 | T | T | F | T | ··· | T |
| Вход 3 | T | T | T | F | ··· | T | Вход 3 | T | T | T | F | ··· | T |
| ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· |
| Вход n | T | T | T | T | ··· | F | Вход n | T | T | T | T | ··· | F |
| Выход | T | F | F | F | ··· | F | Выход | F | T | T | T | ··· | T |
| OR блок. Реализует логическую функцию | NOR блок. Реализует логическую функцию | ||||||||||||
| № набора | 1 | 2 | 3 | 4 | ··· | n + 1 | № набора | 1 | 2 | 3 | 4 | ··· | n + 1 |
| Вход 1 | F | T | F | F | ··· | F | Вход 1 | F | T | F | F | ··· | F |
| Вход 2 | F | F | T | F | ··· | F | Вход 2 | F | F | T | F | ··· | F |
| Вход 3 | F | F | F | T | ··· | F | Вход 3 | F | F | F | T | ··· | F |
| ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· |
| Вход n | F | F | F | F | ··· | T | Вход n | F | F | F | F | ··· | T |
| Выход | F | T | T | T | ··· | T | Выход | T | F | F | F | ··· | F |
Целью анализа полноты покрытия кода является выявление участков кода, которые не выполняются при выполнении тестовых примеров. Тестовые примеры, основанные на требованиях, могут не обеспечивать полного выполнения всей структуры кода. Поэтому для улучшения покрытия проводится анализ полноты покрытия кода тестами, и при необходимости проводятся дополнительные проверки, направленные на выяснение причины недостаточного покрытия и определение необходимых действий по его устранению. Обычно анализ покрытия выполняется с учетом следующих соглашений:
Анализ полноты покрытия тестами может выявить часть исходного кода, которая не исполнялась в ходе тестирования. Для разрешения этого обстоятельства могут потребоваться дополнительные действия в процессе проверки программного обеспечения. Эта неисполняемая часть кода может быть результатом:
if (A B || !B) принципиально невозможно проверить, что часть условия A B будет равна False в случае, когда A=True и B=False, так как вторая часть условия (!B) будет равна True, и общий результат логического выражения будет True ;default в операторе выбора switch, причем входное условие оператора switch может принимать определенные значения, которые он описывает, и, как следствие, ветка default никогда не будет выполнена.Тестовые примеры, рассматриваемые в предыдущих разделах, не существуют сами по себе - каждый тестовый пример проверяет одну ситуацию в работе системы, но вся совокупность тестовых примеров должна полностью проверять всю функциональность системы. В связи с этим описания тестовых примеров объединяют в документы, называемыми тест-планами.
Тест-план представляет собой документ, в котором перечислены либо все тестовые примеры, необходимые для тестирования системы, либо часть тестовых примеров, объединенных по определенному признаку.
Тест-план может быть написан на естественном или формальном языке; в последнем случае возможна передача тест-плана на вход тестового окружения для автоматического выполнения определенных в тест-плане тестовых примеров.
Существует несколько причин для объединения описаний тестовых примеров в единый документ или несколько документов.
Поскольку тестовые примеры пишутся на основании функциональных или тест-требований, при тестировании необходимо удостовериться, что для каждого требования существует хотя бы один тестовый пример. Это достигается введением единой схемы идентификации тестовых примеров (например - сквозной нумерации) и введением ссылок на требования, на основе которых тестовый пример написан.
Тестовые примеры, предназначенные для проверки одних и тех же модулей системы, рационально объединять в смысловые группы. Причина в том, что у таких примеров, как правило, очень похожи входные данные и сценарии, а группировка позволяет выявлять опечатки и ошибки в тестах.
При изменении тестируемой системы в ходе ее жизненного цикла неизбежно приходится изменять тестовые примеры. Общие обзоры тест-требований и тест-планов позволяют выявить, какие тесты должны быть изменены или удалены, а в каких смысловых группах необходимо создание новых тестовых примеров, проверяющих новую функциональность.
Одно из важных свойств тестового примера - его независимость. Это означает, что результат выполнения тестового примера не должен изменяться в зависимости от того, какие тесты выполнялись до него. Как правило, независимость тестовых примеров достигается полной реинициализацией тестового окружения перед выполнением каждого нового тестового примера. Однако, часто возникают ситуации, в которых, для экономии времени выполнения, тесты объединяются в последовательности, где каждый следующий тестовый пример использует состояние тестового окружения или тестируемой системы, достигнутое во время предыдущего теста. Такие связанные тестовые примеры должны быть отдельно помечены для того, чтобы сохранить корректный порядок их следования.
Рассмотрим типовую структуру тест-плана, написанного на естественном языке и содержащего тестовые примеры для проверки работы модуля расчета контрольных сумм.
Каждый тестовый пример в этом тест-плане имеет уникальный номер и ссылку на тест-требование, на основе которого он написан.
Общее описание теста помогает при сопровождении тест-планов - внесении изменений при изменении системы, инспекциях тест-планов, выявляющих несогласованность и т.п.
Также в каждом тестовом примере обязательно перечислены все входные значения и ожидаемые выходные значения, а также сценарий, описывающий последовательность действий, которые необходимо выполнить тестовому окружению для выполнения тестового примера.
Тестовый пример 1 Номер тест-требования: 2а, 2b Описание теста: В данном тесте проверяется правильность вычисления значения контрольной суммы (поля CRC) при непустом значении поля CRC и нулевых значениях элементов записи. Входные данные: CRC = 12345, A=0, B=0, C=0, D=0 Ожидаемые выходные данные: CRC = 0, A=0, B=0, C=0, D=0, Empty = TRUE Сценарий теста: 1. Установка значения поля CRC в 12345 2. Установка значений полей A-F в 0 3. Вызов функции Set_CRC 4. Проверка значений CRC на 0 и Empty на TRUE
Тестовый пример 2 Номер тест-требования: 2a Описание теста: В данном тесте проверяется соответствие алгоритма вычисления поля CRC, заданному в спецификации требований. Входные данные: CRC = 0, A-D заполнены байтами 01010101b Ожидаемые выходные данные: CRC = 0111100b, Empty = FALSE Сценарий теста: 1. Установка значения поля CRC в 0 2. Заполнение байт полей A-D байтами 01010101b 3. Вызов функции Set_CRC 4. Проверка значений CRC на 0111100b и Empty на FALSE
Тестовый пример 3 Номер тест-требования: 2a Описание теста: В данном тесте проверяется неизменность полей A-F записи при вычислении поля CRC (подсчете контрольной суммы). Входные данные: CRC = 0, A-D заполнены байтами 01010101b Ожидаемые выходные данные: A-D заполнены байтами 01010101b, Сценарий теста: 1. Установка значения поля CRC в 0 2. Заполнение байт полей A-D байтами 01010101b 3. Вызов функции Set_CRC 4. Проверка значений байт полей A-D на 01010101b
Такая структура тест-плана позволяет описывать тестовые примеры с совершенно различными наборами входных и выходных данных и сценариями, однако при большом количестве тестовых примеров эта схема станет слишком громоздкой. Позднее будут рассмотрены табличные формы представления тест-планов, позволяющие записывать их более компактно.
В результате выполнения каждого тестового примера тестовое окружение сравнивает ожидаемые и реальные выходные значения. В случае, если эти значения совпадают, тест считается пройденным, т.к. система выдала именно те выходные значения, которые ожидались; в противном случае тест считается не пройденным.
Каждый непройденный тест потенциально указывает на потенциальный дефект в тестируемой системе, а общее их количество позволяет оценивать качество тестируемого программного кода и объем изменений, которые необходимо в него внести для устранения дефектов.
Для построения такой интегральной оценки после выполнения всех тестовых примеров тестовым окружением собирается статистика выполнения, которая, как правило, записывается в файл отчета о выполнении тестов. Существует несколько степеней подробности статистики выполнения тестов:
Например,
180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed Invoking test case 2 … Failed Invoking test case 3 … Failed <…> Invoking test case 200 … Passed Final stats: 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 B = 450 B = 0 Message = "Submenu 1" Message = "" --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 B = 0 B = 300 Message = "" Message = "Main Menu" --- <…> Invoking test case 200 … Passed --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 FAIL B = 450 B = 0 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "Submenu 1" Message = "" FAIL --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 FAIL B = 0 B = 300 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "Main Menu" FAIL --- <…> Invoking test case 200 … Passed --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Например,
Invoking test case 1 … Passed A = 0 A = 0 P B = 0 B = 0 P C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "" P --- Invoking test case 2 … Failed Expected values: Actual values: A = 200 A = 0 FAIL B = 450 B = 0 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "Submenu 1" Message = "" FAIL --- Invoking test case 3 … Failed Expected values: Actual values: A = 0 A = 200 FAIL B = 0 B = 300 FAIL C = 500 C = 500 P D = 600 D = 600 P Message = "" Message = "Main Menu" FAIL --- <…> Invoking test case 200 … Passed Message = "Submenu 1" Message = "Submenu 1 P Prompt = ">" Prompt = ">" P --- Final Stats 180 test cases passed 20 test cases failed 200 test cases total
Более детально различные форматы отчетов о тестировании будут рассмотрены позднее, а пока остановимся более подробно на важном критерии оценки качества системы тестов и степени полноты тестирования системы - уровне покрытия программного кода тестами.
Одна из оценок качества системы тестов - это ее полнота, т.е. величина той части функциональности системы, которая проверяется тестовыми примерами. Обычно за меру полноты берут отношение объема проверенной части системы к ее объему в целом. Полная система тестов позволяет утверждать, что система реализует всю функциональность, указанную в требованиях, и, что еще более важно, - не реализует никакой другой функциональности.
Один из часто используемых методов определения полноты системы тестов является определение отношения количества тест-требований, для которых существуют тестовые примеры, к общему количеству тест-требований. Т.е. в данном случае речь идет о покрытии тестовыми примерами тест-требований. В качестве единицы измерения степени покрытия здесь выступает процент тест-требований, для которых существуют тестовые примеры, называемый процентом покрытых тест-требований.
Покрытие требований позволяет оценить степень полноты системы тестов по отношению к функциональности системы, но не позволяет оценить полноту по отношению к ее программной реализации. Одна и та же функция может быть реализована при помощи совершенно различных алгоритмов, требующих разного подхода к организации тестирования.
Для более детальной оценки полноты системы тестов при тестировании стеклянного ящика анализируется покрытие программного кода, называемое также структурным покрытием.
Во время работы каждого тестового примера выполняется некоторый участок программного кода системы; при выполнении всей системы тестов выполняются все участки программного кода, которые задействует эта система тестов. В случае, если существуют участки программного кода, не выполненные при выполнении системы тестов, система тестов потенциально неполна (т.е. не проверяет всю функциональность системы), либо система содержит участки защитного кода или неиспользуемый код (например, "закладки" или задел на будущее использование системы). Таким образом, отсутствие покрытия каких-либо участков кода является сигналом к переработке тестов или кода (а иногда - и требований).
К анализу покрытия программного кода можно приступать только после полного покрытия требований. Полное покрытие программного кода не гарантирует того, что тесты проверяют все требования к системе. Одна из типичных ошибок начинающего тестировщика - начинать с покрытия кода, забывая про покрытие требований.
Для обеспечения полного покрытия программного кода на данном уровне необходимо, чтобы в результате выполнения тестов каждый оператор был выполнен хотя бы один раз.
Особенность данного уровня покрытия состоит в том, что на нем затруднен анализ покрытия некоторых управляющих структур.
Например, для полного покрытия всех строк следующего участка программного кода на языке 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, даст слишком низкий уровень покрытия.
Для обеспечения полного покрытия по данному методу каждая точка входа и выхода в программе и во всех ее функциях должна быть выполнена по крайней мере один раз, и все логические выражения в программе должны принять каждое из возможных значений хотя бы один раз, - таким образом, для покрытия по веткам требуется как минимум два тестовых примера.
Также данный метод называют: .
В отличие от предыдущего уровня покрытия данный метод учитывает покрытие условных операторов с пустыми ветками. Так, для покрытия по веткам участка программного кода
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.
Для более полного анализа компонент условий в логических операторах существует несколько методов, учитывающих структуру компонент условий и значения, которые они принимают при выполнении тестовых примеров.
Для обеспечения полного покрытия по данному методу каждая компонента логического условия в результате выполнения тестовых примеров должна принимать все возможные значения, но при этом не требуется, чтобы само логическое условие принимало все возможные значения. Так, например, при тестировании следующего фрагмента:
if (condition1 | condition2) functionA(); else functionB();
для покрытия по условиям потребуется два тестовых примера:
(1) Вход: condition1 = true, condition2 = false (2) Вход: condition1 = false, condition2 = true.
При этом значение логического условия будет принимать значение только true, таким образом, при полном покрытии по условиям не будет достигаться покрытие по веткам.
Данный метод сочетает требования предыдущих двух методов - для обеспечения полного покрытия необходимо, чтобы как логическое условие, так и каждая его компонента приняла все возможные значения.
Для покрытия рассмотренного выше фрагмента с условием condition1 | condition2 потребуется 2 тестовых примера:
1. Вход: condition1 = true, condition2 = true 2. Вход: condition1 = false, condition2 = false.
Однако, эти два тестовых примера не позволят протестировать правильность логической функции - вместо OR в программном коде могла быть ошибочно записана операция AND.
Для выявления неверно заданных логических функций был предложен метод покрытия по всем условиям. При данном методе покрытия должны быть проверены все возможные наборы значений компонент логических условий. Т.е. в случае n компонент потребуется 2n тестовых примеров, каждый из которых проверяет один набор значений, Тесты, необходимые для полного покрытия по данному методу, дают полную таблицу истинности для логического выражения.
Несмотря на очевидную полноту системы тестов, обеспечивающей этот уровень покрытия, данный метод редко применяется на практике в связи с его сложностью и избыточностью.
Еще одним недостатком метода является зависимость количества тестовых примеров от структуры логического выражения. Так, для условий, содержащих одинаковое количество компонент и логических операций:
a b (c || (d e)) ((a || b) (c || d)) e
потребуется разное количество тестовых примеров. Для первого случая для полного покрытия нужно 6 тестов, для второго - 11.
Для уменьшения количества тестовых примеров при тестировании логических условий фирмой Boeing был разработан модифицированный метод покрытия по веткам/условиям (Modified Condition/
Для обеспечения полного покрытия по этому методу необходимо выполнение следующих условий:
Покрытие по этой метрике требует достаточно большого количества тестов для того, чтобы проверить каждое условие, которое может повлиять на результат выражения, однако это количество значительно меньше, чем требуемое для метода покрытия по всем условиям. В таблице 6.1 приведены примеры тестовых наборов, необходимых для тестирования логических блоков по MC/DC. Так, например, для блока OR достаточно n+1 тестовых примеров, где n - количество входов логического блока. Первый тестовый пример показывает, что при нулевых значениях входов значение выхода также нулевое. В каждом из следующих n примеров значение каждого входа устанавливается в 1, чем показывается независимое влияние входов на значение выхода.
| AND блок. Реализует логическую функцию | |||||||||||||
| № набора | 1 | 2 | 3 | 4 | ··· | n + 1 | № набора | 1 | 2 | 3 | 4 | ··· | n + 1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Вход 1 | T | F | T | T | ··· | T | Вход 1 | T | F | T | T | ··· | T |
| Вход 2 | T | T | F | T | ··· | T | Вход 2 | T | T | F | T | ··· | T |
| Вход 3 | T | T | T | F | ··· | T | Вход 3 | T | T | T | F | ··· | T |
| ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· |
| Вход n | T | T | T | T | ··· | F | Вход n | T | T | T | T | ··· | F |
| Выход | T | F | F | F | ··· | F | Выход | F | T | T | T | ··· | T |
| OR блок. Реализует логическую функцию | NOR блок. Реализует логическую функцию | ||||||||||||
| № набора | 1 | 2 | 3 | 4 | ··· | n + 1 | № набора | 1 | 2 | 3 | 4 | ··· | n + 1 |
| Вход 1 | F | T | F | F | ··· | F | Вход 1 | F | T | F | F | ··· | F |
| Вход 2 | F | F | T | F | ··· | F | Вход 2 | F | F | T | F | ··· | F |
| Вход 3 | F | F | F | T | ··· | F | Вход 3 | F | F | F | T | ··· | F |
| ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· | ··· |
| Вход n | F | F | F | F | ··· | T | Вход n | F | F | F | F | ··· | T |
| Выход | F | T | T | T | ··· | T | Выход | T | F | F | F | ··· | F |
Целью анализа полноты покрытия кода является выявление участков кода, которые не выполняются при выполнении тестовых примеров. Тестовые примеры, основанные на требованиях, могут не обеспечивать полного выполнения всей структуры кода. Поэтому для улучшения покрытия проводится анализ полноты покрытия кода тестами, и при необходимости проводятся дополнительные проверки, направленные на выяснение причины недостаточного покрытия и определение необходимых действий по его устранению. Обычно анализ покрытия выполняется с учетом следующих соглашений:
Анализ полноты покрытия тестами может выявить часть исходного кода, которая не исполнялась в ходе тестирования. Для разрешения этого обстоятельства могут потребоваться дополнительные действия в процессе проверки программного обеспечения. Эта неисполняемая часть кода может быть результатом:
if (A B || !B) принципиально невозможно проверить, что часть условия A B будет равна False в случае, когда A=True и B=False, так как вторая часть условия (!B) будет равна True, и общий результат логического выражения будет True ;default в операторе выбора switch, причем входное условие оператора switch может принимать определенные значения, которые он описывает, и, как следствие, ветка default никогда не будет выполнена.Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.