Научная статья на тему 'Анализ и тестирование программ на основе алгебраической модели'

Анализ и тестирование программ на основе алгебраической модели Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
483
86
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ / ВЕРИФИКАЦИЯ / ТЕСТИРОВАНИЕ / АВТОМАТИЗАЦИЯ / СИМВОЛЬНОЕ ВЫПОЛНЕНИЕ / СЕМАНТИЧЕСКИЙ АНАЛИЗ / SOFTWARE / VERIFICATION / TESTING / AUTOMATION / SYMBOLIC EXECUTION / SEMANTIC ANALYSIS

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Вигура Антон Николаевич

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

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Вигура Антон Николаевич

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

ALGEBRAIC MODEL-BASED PROGRAM ANALYSIS AND TESTING

Software testing automation based on the structural criterion and the program symbolic execution is considered. A program algebraic model is proposed on whose basis the algorithms of the control graph building and the symbolic execution have been developed and a software testing automation system has been implemented.

Текст научной работы на тему «Анализ и тестирование программ на основе алгебраической модели»

Информационные технологии Вестник Нижегородского университета им. Н.И. Лобачевского, 2011, № 5 (1), с. 185-190

УДК 681.518.5

АНАЛИЗ И ТЕСТИРОВАНИЕ ПРОГРАММ НА ОСНОВЕ АЛГЕБРАИЧЕСКОЙ МОДЕЛИ

© 2011 г. А.Н. Вигура

Нижкгородский государственный технический университет им. Р.Е. Алексеева

anton.vigura@gmail.com

Плступ2са в окдакц2ю 13.09.2011

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

Ксючквые сслва: программное обеспечение, верификация, тестирование, автоматизация, символьное выполнение, семантический анализ.

Введение

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

Отметим, что популярные критерии полноты тестирования (такие как критерий покрытия операторов или покрытия ветвей) основаны на граф-моделях программ. Если при выборе тестов исходить из внутренней структуры программы, представленной в виде графа, можно гарантировать выполнение заданного критерия покрытия. На этом основаны методы структурного тестирования [1], использующие граф-модель программы (в частности, управляющий граф) для получения множества тестовых путей, для которых в дальнейшем определяются соответствующие тестовые наборы. Структурное тестирование требует решения следующих задач:

1) построение граф-модели программы;

2) определение множества тестовых путей по заданному критерию покрытия;

3) проверка реализуемости тестовых путей и определение соответствующих выбранным путям тестовых наборов;

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

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

- граф-модель программы может быть построена по результатам синтаксического анализа [2] программы;

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

- определение тестовых наборов по выбранным путям может быть автоматизировано с помощью символьного выполнения [3].

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

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

1. Синтаксический анализ исходного текста и построение дерева вывода.

2. Построение на основе дерева вывода модели программы в виде выражения.

3. Семантический анализ выражения с использованием набора семантических правил, зависящих от решаемой задачи.

1. Модель программы

Определим сначала понятие алгебраического выражения. Алгебраическое выражение представляет собой один или несколько термов, соединенных между собой знаками операций и знаками последовательности операций (скобками). Каждый терм характеризует некоторый объект, например числовую константу или символ. Формально выражение можно определить следующим образом.

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

Пусть Terms — множество термов, т.е. таких элементарных объектов, как константы и идентификаторы. Это множество будет содержать все возможные константы и идентификаторы.

Пусть Expr — множество выражений. Очевидно, что каждый терм является выражением, поэтому Terms с Expr . Все прочие элементы данного множества имеют вид:

e = (o, a): o e Op, a e Expraigs(o).

В итоге множество выражений может быть определено следующим образом:

Expr = Terms u {(o, a): o e Op, a e Expraigs(o)}.

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

Определим возможные операции в модели программы:

• Арифметические и логические операции, унарные и бинарные (+, -, *, /).

• Операции сравнения (= , !=, <, >, <=, >=).

• Операция присваивания a: =b.

• Операция индексации массива a[b].

• Операция «запятая» (a,b), заключающаяся в последовательном выполнении операндов.

В качестве значения операции используется значение последнего операнда.

• Операция ветвления if(a,b,c), возвращающая Ь, если условие а истинно (не равно нулю), иначе возвращающая с.

• Операция цикла с предусловием while(a,b). Операнд Ь будет выполняться до тех пор, пока условие не станет ложным (равным нулю).

• Операция цикла с постусловием do(a,b). Операнд Ь будет выполняться до тех пор, пока условие не станет ложным (равным нулю).

• Специальные операции vаrdef(a) и funcdef(a,b). Показывают соответственно определение переменной а и функции а с телом Ь.

• Специальные операции 1аЬе1(а) и goto(a), означающие, соответственно, определение метки а и безусловный переход на метку а.

• Операция возврата значения геШт(а). Приводит к окончанию вычисления, а значение выражения становится равным а.

• Операция вызова подпрограммы са11(а, Ь). Вызов подпрограммы а со списком параметров Ь.

Данная модель обладает следующими свойствами:

• позволяет выполнять операции компьютерной алгебры, аналогичные выполняемым над выражениями, делая возможной подстановку значений и преобразования;

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

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

2. Семантический анализ программ

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

а б

Рис. 1. Фрагменты управляющего графа для различных конструкций программы

2.І. Пл^олкнж утоавсяющкгл гоафа

У^авснющ^ гоаф noлгоаммы (УГП) является одной из основных диагностических моделей в структурном тестировании. В УГП вершины соответствуют элементам программы (операторам, линейным участкам и т.п.), а дуги

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

G = (V,E,s,e),s є V,e є V,

где V - множество вершин, E є V x V - множество дуг, s - входная вершина, e - выходная вершина. Введем также следующие обозначения: V (G ) - множество вершин графа G, E(G) -множество дуг графа G, start(G) - входная вершина графа G, end (G) - выходная вершина графа G. Путь в графе может быть представлен как упорядоченная последовательность номеров вершин. Определим через start(P) и end(P) соответственно начальную и конечную вершины пути P. Покрытие графа представляет собой такое множество путей, что каждая дуга принадлежит хотя бы одному пути из этого множества.

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

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

Va = V([a ]]) - множество вершин графа выражения a;

E а = E ([[a ]]) - множество дуг графа выражения a;

sa = start ([[a]]) - входная вершина графа выражения a;

ea = end ([[a]]) - выходная вершина графа выражения a;

v0 - фиктивная вершина, не соответствующая ни одному оператору;

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

Одиночному оператору соответствует одна вершина графа (рис. 1а):

[[a ] = ({va },0 ,v,v)

Последовательность операторов (рис. 1б):

Ы= (Va U Vb,Ea U Eb U{(eb , sa )

Если при обработке этого правила обнаруживается, что ea = v0 , то оператор b недостижим, что является ошибкой в программе. При этом в получаемом графе появляется еще одна вершина без преемников.

Оператор ветвления (рис. 1в):

(a,b,c)]]= (Va u Vb u Vc u{vo},

Ea U Eb U Ec U {(ea,sb Mea,sc }

(eb,v0 ),(ec,v0 )},sa,v0).

Цикл с предусловием (рис. І г):

[[while(a,b )]] = = (Va U Vb,Ea U Eb U {(ea ,sb Meb , sa )},sa ,e a У

Цикл с постусловием (рис. Ід):

\do(a,b )]] =

= (Va U Vb,Ea U Eb U {(ea , sb ) (eb ,sa )},sb , ea I

Если в программе присутствовали такие операторы, как goto, return (т.е. операции безусловного перехода), построение графа несколько усложняется. Для операции возврата значения имеем следующее семантическое правило:

[return(a)]] = (Va U {vret },Ea U {(ea , v,et )} sa , v0 I

где vret - вершина, соответствующая точке выхода из функции.

Выходная вершина графа здесь не определена (на ее месте стоит v0 ), поскольку return осуществляет прекращение выполнения подпрограммы и возврат значения. Поэтому после построения графа для подпрограммы из его множества дуг для корректности нужно удалить все пары, содержащие v0 .

Определим также семантические правила для операций label и goto:

[[IabeI(a)]] = ({viM („ )} 0,viM („) ,vlM (a)),

[[goto(a)]] = ({vgo(o(a),vIM (a)},

{(vgoto(a),viabel (a))},vgo,o(a),v0)

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

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

2.2. Сuмвлсbнлк вътллнктк noлгоаммы

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

Для заданного пути P определим понятие функцш nymu. Для этого составим кортеж Vars є Exprn из символов всех объявленных в подпрограмме переменных (n - число переменных). Функция пути /P : Exprn ^ Exprn ставит в соответствие переменным их символьные значения (зависящие от исходных значений переменных в начальной точке пути), полученные при прохождении заданного пути P в программе. При этом путь P не обязательно должен проходить от входной вершины до выходной, он также может представлять собой некоторый участок, в том числе состоять из одной вершины.

yc^eue nymu — это условие, накладываемое на входные данные, выполнение которого приводит к прохождению в программе заданного пути. Условие пути может быть записано как предикат cP : Exprn ^ {0,І}.

Пусть G — управляющий граф программы, а P1 и P2 - пути в нем, такие, что

(end(P1), start(P2)) e E(G). Определим путь P = P1 * P2, где «*» - операция конкатенации.

Функция пути по определению показывает зависимость значений переменных на выходе от их значений на входе пути. Поэтому, если известны функции fP1 и fP 2, можно определить функцию объединенного пути fP как композицию функций составляющих его участков: fp (Vars) = fp2 (fpi (Vars)) = fp2 о fpi.

Условие прохождения составного пути равно конъюнкции условий прохождения составляющих его участков: cp = cP1 л cP2.

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Эти простые свойства приводят к алгоритму определения функции и условия пути.

Алгоритм символьного выполнения для пути P. Обозначим через len(P) длину пути P, через

op(Pj) соответствующий вершине Pi оператор

программы в принятой алгебраической модели, а через vertex(op) — соответствующую оператору op вершину графа.

1. Пусть i = 0, f = Vars, с = 1.

2. Сравним i с len(P). Если i > len(P), прерываем работу алгоритма. В кортеже f будут содержаться выражения для функции пути, а в выражении с — условие прохождения.

3. Определяем (fi,ci) = d°p(Pi)]]

4. f ^ f (f);c ^с лс.

5. Увеличиваем i на 1 и переходим к шагу 2.

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

subst(e) =

e.val, если e e Terms и e.val определено,

< e, если e e Terms и e.val не определено, (o,(subst(al),...,subst(an))), еслиe = (o,a)e Expr.

Здесь e.val — текущее символьное значение переменной.

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

— функция пути, с — условие пути.

Семантическое правило для простых операторов без побочных эффектов:

[[a]] = (Vars, 1).

Функция пути для оператора присваивания вида a=b имеет вид f(,..,a,...) = (...,b,...) (т.е. изменяется только одна переменная). Кратко

Рис. 2. Последовательность обработки текста программы

можно записать предыдущее выражение в виде a ^ b. Условие пути для оператора присваивания тождественно равно истине, следовательно, семантическое правило записывается так:

[[a = b ]] = (a ^ b, 1).

Оператор ветвления:

[[if (a, b, с)]] =

(Vars, subst(a)), если vertex(b) = Pi+1;

(Vars, —subst(a)) в противном случае.

Здесь i — номер текущей обрабатываемой вершины пути (соответствующей операции ветвления). Условие прохождения будет равно условию ветвления в том случае, когда следующая вершина пути лежит в ветви b. В противном случае условие прохождения равно инверсии условия ветвления.

Цикл с предусловием:

[[while (a, b)]] =

(Vars, subst (a)), если vertex(b) = Pi+1;

(Vars, —subst(a)) в противном случае.

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

[[do( a, b)]] =

(Vars, subst(a)), если vertex(b) = Pi+1; (Vars, —subst(a)) в противном случае.

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

3. Программная реализация

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

• Лексический и синтаксический анализаторы (с возможностью генерации анализаторов по произвольной LR(1)-грамматике, заданной на специальном языке).

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

• Интерпретатор семантических правил, который, собственно, и выполняет анализ.

• Описание грамматики языка С и модуль построения алгебраической модели программы, написанной на С.

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

• Программа построения минимальных покрытий графов, в том числе с циклами.

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

Заключение

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

В текущей редакции система поддерживает обработку текстов программ, написанных на

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

Список литературы

1. Myers G.J. The Art of Software Testing. Second edition. Wiley, 2004. 234 p.

2. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции / Под ред. В.М. Агафонова. М.: Мир, 1978. 613 с.

3. Борзов Ю.В. Тестирование программ с использованием символического выполнения // Программирование. 1980. №1. С. 51-59.

4. Белоусов А.И., Ткачев С.Б. Дискретная математика: Учеб. для вузов / Под ред. В.С. Зарубина, А.П. Крищенко. 3-е изд., стереотип. М.: Изд-во МГТУ им. Н.Э. Баумана, 2004. 744 с.

ALGEBRAIC MODEL-BASED PROGRAM ANALYSIS AND TESTING

A.N. Vigura

Software testing automation based on the structural criterion and the program symbolic execution is considered. A program algebraic model is proposed on whose basis the algorithms of the control graph building and the symbolic execution have been developed and a software testing automation system has been implemented.

Keywords: software, verification, testing, automation, symbolic execution, semantic analysis.

i Надоели баннеры? Вы всегда можете отключить рекламу.