Оценка качества тестирования ПО. Часть 2: Классификация критериев тестового покрытия
Предыдущая часть закончилась выводом о необходимости использования метрик для оценки качества тестирования и обещанием классифицировать используемые метрики (они же — критерии тестового покрытия). Обещания надо выполнять.
Майерс безусловно прав, определяя тестирование, как процесс исполнения программы с целью обнаружения ошибок [1]. Хотя с моей точки зрения, позитивные определения тоже имеют право на существование, при попытке их проверки «от противного» как раз и получается определение Майерса.
Таким образом, критерии тестового покрытия должны быть нацелены на обнаружение ошибок. Ресурсы на тестирование всегда ограничены, поэтому приходится расставлять приоритеты — на выявление каких ошибок мы нацеливаемся, а какие игнорируем. Игнорировать возможность ошибок определенного вида можно по разным причинам — например, считая их слишком дорогостоящими для выявления, либо маловероятными. Результатом расстановки приоритетов является гипотеза о характере имеющихся в системе ошибок. Дальнейшее тестирование будет нацелено на выявление ошибок такого вида.
При таком подходе первыми отсеиваются «точечные» ошибки — те, которые проявляются в единственной ситуации (на единственном наборе входных данных), которая ничем не выделяется из аналогичных ситуаций. Например, если функция вычисления площади треугольника по трем сторонам работает правильно везде, кроме (137, 108, 96), то обнаружить такую ошибку можно только при большом везении или при исчерпывающем тестировании, которого не бывает. К тому же, не очень понятно, откуда такая ошибка взялась в программе — разве что по злому умыслу разработчика, но с этим надо бороться по-другому. Значит, остаются более или менее регулярные ошибки, которые проявляются на целом классе ситуаций и могут быть обнаружены сравнительно небольшим набором тестов. Например, для рассмотренной функции вычисления площади треугольника, вполне реально обнаружить ошибки, которые проявляются на всех прямоугольных треугольниках, или на всех равнобедренных треугольниках, поскольку тест для этих особых случаев должен присутствовать в хорошем тестовом наборе.
Для поиска регулярных ошибок набор тестов должен содержать представителей каждого класса ситуаций, в которых проявляются регулярные ошибки. А критерий покрытия измеряет долю классов ситуаций, представители которых попали в тестовый набор. Чем больше уровень тестового покрытия, тем больше классов ситуаций покрыто, тем больше регулярных ошибок можно обнаружить.
Каковы источники информации о поведении программы?
- Исходный код программы
Исторически сложилось, что в качестве такого источника используется исходный код самой программы. Таким образом получаются структурные критерии покрытия — на основе потоков управления или потоков данных программы. Такое тестирование называется тестированием методом белого ящика , для создания набора тестов используется знание внутреннего устройства программы. Вычисление уровня достигнутого тестового покрытия при использовании таких критериев может быть автоматизировано. Заметим, что этот результат зависит от реализации системы — используя тот же набор тестов на другой реализации, получим другой уровень тестового покрытия.
Какова адекватность критериев покрытия, основанных на исходном коде программы?
С одной стороны, структурные критерии покрытия используют знание реального устройства программы и могут обеспечить хорошее покрытие кода реализации системы. Но с другой стороны хорошее покрытие кода ещё не означает полного соответствия требованиям — какая-то часть функциональности может просто отсутствовать. А плохое покрытие кода не обязательно является недостатком тестового набора — система может обладать какой-либо функциональностью помимо рассмотренной. То есть, структурные критерии покрытия не позволяют делать выводы о качестве проверки требований к программе.
Исходный код программы может использоваться и для построения критериев покрытия, основанных на гипотезах о характере ошибок.
Структура входных данных
Если исходный код самой программы не доступен, то критерий покрытия может быть сформулирован на основе структуры входных данных программы. Если ошибка проявляется на определенном классе входных данных, почему это может происходить? Это может быть связано либо с логическими особенностями входных данных (так можно выделить четные числа среди всех натуральных, тупоугольные треугольники среди всех треугольников и т.п.), либо с реализационным представлением входных данных (например, при использовании различных классов для представления различных видов объектов в общим интерфейсом — ошибка может содержаться в одном из классов).
Поскольку логические особенности входных данных и их реализационное представление учитываются в коде программы, существует зависимость между уровнем покрытия входных данных и покрытием исходного кода. Однако особенности конкретного использования данных в их структуре не отражаются, поэтому покрытие структуры данных вообще говоря не дает хорошего покрытия кода.
Требования
Ещё одним источником информации для определения критериев покрытия могут являться требования к программе. Обоснованием разделения тестов на классы относительно проверки ими определенных требований к программе является предположение о том, что ошибка в реализации требования проявляется при любой проверке этого требования.
Часто требования формулируются в виде импликации: C => P, где С — условие, а P — предикат, который должен быть выполнен при этом условии. Для критериев покрытия требований используются условия С (предикат P необходим для вынесения вердикта), которые задают ситуацию проверки требования. Эти условия при построении критериев покрытия по требованиям используются аналогично условиям в исходном коде программы, влияющим на поток управления.
Для анализа достигнутого уровня тестового покрытия должно быть установлено соответствие между требованиями и тестами или проведена частичная формализация требований, позволющая автоматически установить это соответствие.
Модели
Хорошим источником информации для определения критериев тестового покрытия явлется формальная модель или спецификация поведения или структуры системы. Классы тестовых ситуаций, извлеченные из модели, часто уточняют классы ситуаций, определенные на основании входных данных или требований. Таким образом, модель позволяет определить более детальные критерии покрытия, чем структура входных данных или набор требований, причем эти критерии покрытия по-прежнему остаются независимыми от реализации. Детали, не отраженные в модели, не будут отражены и критерии покрытия.
Использование критериев покрытия на основе моделей ограничено тем, что далеко не для каждой тестируемой программы доступна формальная модель, а ее создание требует значительных трудозатрат и во многих случаях не оправдано.
В следующей части будут рассмотрены виды критериев покрытия, используемые в рамках технологии UniTESK [2], и способы достижения высокого уровня покрытия для них.
Литература
1. Майерс Г. Искусство тестирования программ. М.: Финансы и статистика, 1982.
2. UniTESK — индустриальная технология надежного тестирования.
Источник
Оценка Покрытия Программы и Проекта
2014-02-02
2653
Мутационный критерий (класс IV)
Стохастические критерии (класс III)
Функциональные критерии (класс II)
Структурные критерии (класс I).
Классы критериев
Требования к идеальному критерию тестирования
Три фазы тестирования
Реализация тестирования разделяется на три этапа:
· Создание тестового набора (test suite) путем ручной разработки или автоматической генерации для конкретной среды тестирования (testing environment).
· Прогон программы на тестах, управляемый тестовым монитором (test monitor, test driver [IEEE Std 829-1983]) с получением протокола результатов тестирования (test log).
· Оценка результатов выполнения программы на наборе тестов с целью принятия решения о продолжении или остановке тестирования.
Основная проблема тестирования — определение достаточности множества тестов для истинности вывода о правильности реализации программы, а также нахождения множества тестов, обладающего этим свойством.
Требования к идеальному критерию:
1. Критерий должен быть достаточным, т.е. показывать, когда некоторое конечное множество тестов достаточно для тестирования данной программы.
2. Критерий должен быть полным, т.е. в случае ошибки должен существовать тест из множества тестов, удовлетворяющих критерию, который раскрывает ошибку.
3. Критерий должен быть надежным, т.е. любые два множества тестов, удовлетворяющих ему, одновременно должны раскрывать или не раскрывать ошибки программы
4. Критерий должен быть легко проверяемым, например вычисляемым на тестах
Для нетривиальных классов программ в общем случае не существует полного и надежного критерия, зависящего от программ или спецификаций.
Поэтому мы стремимся к идеальному общему критерию через реальные частные.
1. Структурные критерии используют информацию о структуре программы (критерии так называемого «белого ящика»)
2. Функциональные критерии формулируются в описании требований к программному изделию (критерии так называемого «черного ящика»)
3. Критерии стохастического тестирования формулируются в терминах проверки наличия заданных свойств у тестируемого приложения, средствами проверки некоторой статистической гипотезы.
4. Мутационные критерии ориентированы на проверку свойств программного изделия на основе подхода Монте-Карло.
Структурные критерии используют модель программы в виде «белого ящика», что предполагает знание исходного текста программы или спецификации программы в виде потокового графа управления. Структурная информация понятна и доступна разработчикам подсистем и модулей приложения, поэтому данный класс критериев часто используется на этапах модульного и интеграционного тестирования (Unit testing, Integration testing).
Структурные критерии базируются на основных элементах УГП, операторах, ветвях и путях.
· Условие критерия тестирования команд (критерий С0) — набор тестов в совокупности должен обеспечить прохождение каждой команды не менее одного раза. Это слабый критерий, он, как правило, используется в больших программных системах, где другие критерии применить невозможно.
· Условие критерия тестирования ветвей (критерий С1) — набор тестов в совокупности должен обеспечить прохождение каждой ветви не менее одного раза. Это достаточно сильный и при этом экономичный критерий, поскольку множество ветвей в тестируемом приложении конечно и не так уж велико. Данный критерий часто используется в системах автоматизации тестирования.
· Условие критерия тестирования путей (критерий С2) — набор тестов в совокупности должен обеспечить прохождение каждого пути не менее 1 раз. Если программа содержит цикл (в особенности с неявно заданным числом итераций), то число итераций ограничивается константой (часто — 2, или числом классов выходных путей).
Функциональный критерий – важнейший для программной индустрии критерий тестирования. Он обеспечивает, прежде всего, контроль степени выполнения требований заказчика в программном продукте. Поскольку требования формулируются к продукту в целом, они отражают взаимодействие тестируемого приложения с окружением. При функциональном тестировании преимущественно используется модель «черного ящика». Проблема функционального тестирования – это, прежде всего, грудоемкость; дело в том, что документы, фиксирующие требования к программному изделию (Software requirement specification, Functional specification и т.п.), как правило, достаточно объемны, тем не менее, соответствующая проверка должна быть всеобъемлющей.
Ниже приведены частные виды функциональных критериев.
• Тестирование пунктов спецификации – набор тестов в совокупности должен обеспечить проверку каждого тестируемого пункта не менее одного раза.
Спецификация требований может содержать сотни и тысячи пунктов требований к программному продукту, и каждое из этих требований при тестировании должно быть проверено в соответствии с критерием не менее чем одним тестом.
• Тестирование классов входных данных – набор тестов в совокупности должен обеспечить проверку представителя каждого класса входных данных не менее одного раза. При создании тестов классы входных данных сопоставляются с режимами использования тестируемого компонента или подсистемы приложения, что заметно сокращает варианты перебора, учитываемые при разработке тестовых наборов. Следует заметить, что, перебирая в соответствии с критерием величины входных переменных (например, различные файлы – источники входных данных), мы вынуждены применять мощные тестовые наборы. Действительно, наряду с ограничениями на величины входных данных, существуют ограничения на величины входных данных во всевозможных комбинациях, в том числе проверка реакций системы на появление ошибок в значениях или структурах входных данных. Учет этого многообразия – процесс трудоемкий, что создает сложности для применения критерия
• Тестирование правил – набор тестов в совокупности должен обеспечить проверку каждого правила, если входные и выходные значения описываются набором правил некоторой грамматики. Следует заметить, что грамматика должна быть достаточно простой, чтобы трудоемкость разработки соответствующего набора тестов была реальной (вписывалась в сроки и штат специалистов, выделенных для реализации фазы тестирования).
• Тестирование классов выходных данных – набор тестов в совокупности должен обеспечить проверку представителя каждого выходного класса, при условии, что выходные результаты заранее расклассифицированы, причем отдельные классы результатов учитывают, в том числе, ограничения на ресурсы или на время (time out).
При создании тестов классы выходных данных сопоставляются с режимами использования тестируемого компонента или подсистемы, что заметно сокращает варианты перебора, учитываемые при разработке тестовых наборов.
• Тестирование функций – набор тестов в совокупности должен обеспечить проверку каждого действия, реализуемого тестируемым модулем, не менее одного раза.
Очень популярный на практике критерий, который, однако, не обеспечивает покрытия части функциональности тестируемого компонента, связанной со структурными и поведенческими свойствами, описание которых не сосредоточено в отдельных функциях (т.е. описание рассредоточено по компоненту). Критерий тестирования функций отчасти объединяет особенности структурных и функциональных критериев. Он базируется на модели «полупрозрачного ящика», где явно указаны не только входы и выходы тестируемого компонента, но также состав и структура используемых методов (функций, процедур) и классов.
• Комбинированные критерии для программ и спецификаций – набор тестов в совокупности должен обеспечить проверку всех комбинаций непротиворечивых условий программ и спецификаций не менее одного раза.
При этом все комбинации непротиворечивых условий надо подтвердить, а условия противоречий следует обнаружить и ликвидировать.
Стохастическое тестирование применяется при тестировании сложных программных комплексов – когда набор детерминированных тестов (X,Y) имеет громадную мощность. В случаях, когда подобный набор невозможно разработать и исполнить на фазе тестирования, можно применить следующую методику:
Разработать программы – имитаторы случайных последовательностей входных сигналов <х>.
Вычислить независимым способом значения <у>для соответствующих входных сигналов <х>и получить тестовый набор (X,Y).
Протестировать приложение на тестовом наборе (X,Y), используя два способа контроля результатов:
♦ Детерминированный контроль – проверка соответствия вычисленного значения увк <у>значению у, полученному в результате прогона теста на наборе <х>– случайной последовательности входных сигналов, сгенерированной имитатором.
♦ Стохастический контроль – проверка соответствия множества значений <ув>, полученного в результате прогона тестов на наборе входных значений <х>, заранее известному распределению результатов F(Y).
В этом случае множество Y неизвестно (его вычисление невозможно), но известен закон распределения данного множества.
Критерии стохастического тестирования:
♦ Статистические методы окончания тестирования – стохастические методы принятия решений о совпадении гипотез о распределении случайных величин. К ним принадлежат широко известные: метод Стьюдента (St), метод Хи-квадрат (х 2 ) и т.п.
♦ Метод оценки скорости выявления ошибок – основан на модели скорости выявления ошибок [12], согласно которой тестирование прекращается, если оцененный интервал времени между текущей ошибкой и следующей слишком велик для фазы тестирования
Постулируется, что профессиональные программисты пишут сразу почти правильные программы, отличающиеся от правильных мелкими ошибками или описками типа – перестановка местами максимальных значений индексов в описании массивов, ошибки в знаках арифметических операций, занижение или завышение границы цикла на 1 и т.п. Предлагается подход, позволяющий на основе мелких ошибок оценить общее число ошибок, оставшихся в программе.
Подход базируется на следующих понятиях:
Мутации – мелкие ошибки в программе.
Мутанты – программы, отличающиеся друг от друга мутациями.
Метод мутационного тестирования – в разрабатываемую программу Р вносят мутации, т.е. искусственно создают программы-мутанты Р1,Р2. Затем программа Р и ее мутанты тестируются на одном и том же наборе тестов (X,Y).
Если на наборе (X,Y) подтверждается правильность программы Р и, кроме того, выявляются все внесенные в программы-мутанты ошибки, то набор тестов (X, Y) соответствует мутационному критерию, а тестируемая программа объявляется правильной.
Если некоторые мутанты не выявили всех мутаций, то надо расширять набор тестов (X,Y) и продолжать тестирование.
Тестирование программы Р по некоторому критерию С означает покрытие множества компонентов программы Р М=
T=
Тест ti неизбыточен, если существует покрытый им компонент mi из М(Р,С), не покрытый ни одним из предыдущих тестов t1. ti-1. Каждому ti соответствует неизбыточный путь рi – последовательность вершин от входа до выхода.
V(P,C) – сложность тестирования Р по критерию С – измеряется max числом неизбыточных тестов, покрывающих все элементы множества М(Р,С).
DV(P,C,T) – остаточная сложность тестирования Р по критерию С – измеряется max числом неизбыточных тестов, покрывающих элементы множества М(Р,С), оставшиеся непокрытыми, после прогона набора тестов Т. Величина DV строго и монотонно убывает от V до 0.
TV(P,C,T) = (V-DV)/V – оценка степени тестированности Р по критерию С.
Критерий окончания тестирования TV(P,C,T) ³ L, где (0 £ L £ 1). L – уровень оттестированности, заданный в требованиях к программному продукту.
Рис. 1.1. Метрика оттестированности приложения
Рассмотрим две модели программного обеспечения, используемые при оценке оттестированноси.
Для оценки степени оттестированности часто используется УГП – управляющий граф программы. УГП многокомпонентного объекта G (рис. 1.2, рис. 1.8), содержит внутри себя два компонента G1 и G2, УГП которых раскрыты.
Рис. 1.2. Плоская модель УГП компонента G
В результате УГП компонента G имеет такой вид, как если бы компоненты G1 и G2 в его структуре специально не выделялись, а УГП компонентов G1 и G2 были вставлены в УГП G. Для тестирования компонента G в соответствии с критерием путей потребуется прогнать тестовый набор, покрывающий следующий набор трасс графа G (рис. 1.3):
Набор трасс, необходимых для покрытия плоской модели УГП компонента G
Pi(G) | = 1-2-3-4-5-6-7-10; |
P2(G) | = 1-2-3-4-6-7-10; |
P3(G) | — 1-2-11-16-18-14-15-7-10; |
P4(G) | = 1-2-11-16-17-14-15-7-10; |
P5(G) | = 1-2-11-16-12-13-14-15-7-10; |
P6(G) | = 1-2-19-20-23-22-7-10; |
P7(G) | = 1-2-19-20-21-22-7-10; |
Рис. 1.4. Иерархическая модель УГП компонента G
УГП компонента G, представленный в виде иерархической модели, приведен на рис. 1.4 и рис. 1.9. В иерархическом УГП G входящие в его состав компоненты представлены ссылками на свои УГП G1 и G2 (рис. 1.10 и рис. 1.9)
Рис. 1.5. Иерархическая модель: УГП компонентов G1 и G2
Для исчерпывающего тестирования иерархической модели компонента G в соответствии с критерием путей требуется прогнать следующий набор трасс (рис. 1.6):
P 1 (G) | = 1-2-3-4-5-6-7-10; |
P 2 (G) | = 1-2-3-4-6-7-10; |
P 3 (G) | = 1-2-8-7-10; |
P 4 (G) | = 1-2-9-7-10. |
Рис. 1.6. Набор трасс, необходимых для покрытия иерархической модели УГП компонента G
Приведенный набор трасс достаточен при условии, что компоненты G1 и G2 в свою очередь исчерпывающе протестированы. Чтобы обеспечить выполнение этого условия в соответствии с критерием путей, надо прогнать все трассы рис. 1.7.
Рис. 1.7. Набор трасс иерархической модели УГП, необходимых для покрытия УГП компонентов G1 и G2
Оценка степени тестированности плоской модели определяется долей прогнанных трасс из набора необходимых для покрытия в соответствии с критерием С.
– тестовый путь (tj) в графе G плоской модели равен 1, если он протестирован (прогнан), или 0, если нет.
Например, если в УГП (рис. 1.5) тесты t6 и t8, которым соответствуют трассы Р6 и Р8, не прогнаны, то в соответствии с соотношением (1) для TV(G,C) степень тестированности будет оценена в 0.71.
Оценка тестированности иерархической модели определяется на основе учета оценок тестированности компонентов. Если трасса некоторого теста tj УГП G включает узлы, представляющие компоненты Gj1. Gjm, оценка TV степени тестированности которых известна, то оценка тестированности PTj(G) при реализации этой трассы определяется не 1, а минимальной из оценок TV для компонентов.
Интегральная оценка определяется соотношением (2):
, где
PTi(G) – тестовый путь (ti) в графе G равен 1, если протестирован, или 0, если нет. В путь РТ <графа G может входить j узлов модулей Gij со своей степенью тестированности TV(Gij,C) из которых мы берем min, что дает худшую оценку степени тестированности пути.
Источник
Оценка оттестированности проекта: метрики и методика интегральной оценки
Оценка Покрытия Программы и Проекта
Тестирование программы Р по некоторому критерию С означает покрытие множества компонентов программы P М =
Тест ti неизбыточен, если существует покрытый им компонент mi из M(P,C) , не покрытый ни одним из предыдущих тестов t1. ti-1 . Каждому ti соответствует неизбыточный путь pi — последовательность вершин от входа до выхода.
V(P,C) — сложность тестирования Р по критерию С — измеряется max числом неизбыточных тестов, покрывающих все элементы множества M(P,C)
DV (P,C,Т) — остаточная сложность тестирования Р по критерию С — измеряется max числом неизбыточных тестов, покрывающих элементы множества M(P,C) , оставшиеся непокрытыми, после прогона набора тестов Т . Величина DV строго и монотонно убывает от V до 0 .
TV(P,C,Т) = (V- DV )/V — оценка степени тестированности Р по критерию С .
Критерий окончания тестирования TV(P,C,Т) >= L , где (0 . L — уровень оттестированности, заданный в требованиях к программному продукту.
Рассмотрим две модели программного обеспечения, используемые при оценке оттестированности.
Для оценки степени оттестированности часто используется УГП — управляющий граф программы . УГП многокомпонентного объекта G (Рис. 4.2, Пример 4.4), содержит внутри себя два компонента G1 и G2 , УГП которых раскрыты.
В результате УГП компонента G имеет такой вид, как если бы компоненты G1 и G2 в его структуре специально не выделялись, а УГП компонентов G1 и G2 были вставлены в УГП G . Для тестирования компонента G в соответствии с критерием путей потребуется прогнать тестовый набор , покрывающий следующий набор трасс графа G (Пример 4.1):
УГП компонента G , представленный в виде иерархической модели, приведен на Рис. 4.3, Пример 4.5. В иерархическом УГП G входящие в его состав компоненты представлены ссылками на свои УГП G1 и G2 (Рис. 4.4, Пример 4.5)
Для исчерпывающего тестирования иерархической модели компонента G в соответствии с критерием путей требуется прогнать следующий набор трасс (Пример 4.2):
Приведенный набор трасс достаточен при условии, что компоненты G1 и G2 в свою очередь исчерпывающе протестированы. Чтобы обеспечить выполнение этого условия в соответствии с критерием путей, надо прогнать все трассы Пример 4.3.
Источник