2010 г.
Архитектура среды тестирования на основе моделей, построенная на базе компонентных технологий
Кулямин В. В.
Институт системного программирования РАН (ИСП РАН), Москва
Назад Содержание Вперёд 2. Тестирование на основе моделей и инструменты тестирования
Тестирование на основе моделей (model based testing) [7,8] представляет собой подход к тестированию, в рамках которого тесты строятся вручную, автоматизированным образом или генерируются полностью автоматически на основе модели поведения тестируемой системы и модели ситуаций, связанных с ее работой.
- Модель поведения (behavior model) формализует требования к тестируемой системе, т.е. описывает, какие внешние воздействия на нее в каких ситуациях допустимы, и как она должна реагировать на эти воздействия, как она должна работать.
Модель поведения служит основой для тестового оракула [9-11] — компонента или процедуры, производящей оценку поведения системы во время тестирования.
Чаще всего при тестировании используются модели в виде автоматов разного вида: наиболее простые конечные автоматы, расширенные автоматы, системы помеченных переходов [7], Statecharts [12,13], временные автоматы [14,15] и т.д. Однако в таком качестве можно использовать другие разновидности моделей: контрактные спецификации в виде пред- и постусловий операций, алгебраические спецификации в виде правил эквивалентности различных цепочек вызовов операций, трассовые или сценарные модели, описывающие возможные последовательности воздействий и реакций системы.
- Модель ситуаций (situation model) формализует структуру возможных тестовых ситуаций, составляющими которых являются внешние воздействия и состояния самой системы и ее окружения, определяет различные классы ситуаций и их важность с точки зрения контроля качества. Обычно такая модель определяет конечный набор классов эквивалентности ситуаций, подразумевая, что при тестировании достаточно проверить работу системы хотя бы в одной ситуации из каждого класса. Достаточно часто также для задания модели ситуаций используется конечный набор элементарных событий, при этом каждая ситуация соответствует некоторому множеству таких событий. Примером такого события может являться выполнение заданной инструкции в коде тестируемой системы. В более сложных случаях определяемые классы ситуаций могут пересекаться, и им могут приписываться приоритеты и веса, показывающие, насколько важно проверить одну из ситуаций такого класса.
Модель ситуаций используется для решения двух тесно связанных задач: определения критерия адекватности или полноты тестирования [16] и определения числовых метрик полноты тестирования. Заметим, что под полнотой тестирования здесь имеется в виду удовлетворение определенному критерию (скажем, достижение 80% покрытия кода), а совсем не исчерпывающий перебор всех практически возможных ситуаций. Критерий полноты тестирования задает свойства набора тестов, позволяющие считать его достаточно хорошо представляющим разнообразное поведение проверяемой системы для решения некоторого круга задач и больше тестов не создавать. Метрики полноты тестов представляются в терминах процентной доли проверяемых ими классов ситуаций разных видов. Обычно в качестве критерия полноты тестирования устанавливается достижение какого-то значения метрики, но при этом само значение метрики бывает полезно знать дополнительно. Чаще всего полнота тестирования определяется на основе покрытия классов эквивалентных ситуаций или элементарных событий, и в этих случаях говорят о критерии тестового покрытия, метрике тестового покрытия, а достигнутый в ходе тестирования процент покрытых классов ситуаций называют тестовым покрытием.
Построение тестов на основе моделей заключается в том, что создается (извлекается из проектных документов или, реже всего, берется откуда-то в готовом виде) модель поведения тестируемой системы, создается модель ситуаций, отражающая основные приоритеты и риски проекта и, чаще всего, использующая структурные элементы модели поведения, и затем строится (генерируется автоматически, создается вручную, или разрабатывается с существенной помощью инструментов) комплект тестов, проверяющих соответствие между реальным поведением тестируемой системы и ее моделью поведения. При этом тестовый набор создается так, чтобы он удовлетворял критерию полноты тестирования, заданному моделью ситуаций.
Используемые для построения тестов методы можно разделить три типа.
- Вероятностные методы используют псевдослучайную генерацию данных элементарных типов, псевдослучайное комбинирование их в более сложные структуры и псевдослучайную же генерацию последовательностей тестовых воздействий, если необходимо проверять поведение системы в разных состояниях. При этом полноту тестирования стараются обеспечить за счет большого количества разнообразных тестов, так как построение каждого отдельного теста требует небольших затрат.
- Нацеленные методы, наоборот, строят тестовые данные и последовательности целенаправленно, так, чтобы те удовлетворяли определенным свойствам, чаще всего — реализовывали ситуации из определенных классов, задаваемых моделью ситуаций. Критерий полноты тестирования при использовании таких методов удовлетворяется близким к минимальному количеством тестов, но построение каждого теста обычно требует значительных усилий человека и/или затрат вычислительных ресурсов.
- Комбинаторные методы строят тестовые данные и последовательности с помощью комбинирования различных типов их элементов по определенным схемам. Они занимают промежуточное положение: на создание одного теста нужно существенно меньше усилий, чем при нацеленном построении, но несколько больше, чем при вероятностном. Тестовый набор получается значительно больше, чем при нацеленном тестировании, но много меньше, чем при вероятностном, хотя в нем и достигается большее разнообразие. Кроме того, комбинаторные методы обычно гарантируют, что в полученном наборе нет совершенно идентичных тестов, которые очень часто возникают в случайно сгенерированных наборах. Некоторые комбинаторные методы, использующие эффективную фильтрацию «лишних», не вносящих собственный вклад в достижение полноты тестов, вполне сопоставимы с нацеленными методами по характеристикам получаемого тестового набора. Примером служат техники построения тестов на основе автоматных моделей, создающие тесты в виде набора путей по графу переходов автомата, минимизируя его с точки зрения покрытия и проверки всех возможных состояний и переходов.
Требования к представлениям моделей
Инструменты, поддерживающие тестирование на основе моделей, должны работать с какими-то представлениями моделей поведения и моделей ситуаций. Для полноценной поддержки этого подхода к тестированию и повышения удобства его использования в практике разработки ПО, эти представления должны обладать следующими свойствами.
- Модели поведения.
- Средства для описания требований в разных стилях, как минимум в виде чистых декларативных ограничений (утверждений о свойствах входных данных операций и их результатов), в виде контрактных спецификаций (пред- и постусловий операций), использующих модельное состояние, в виде исполнимых моделей, определяющих способ работы проверяемой системы на более высоком уровне абстракции. Это требование обусловлено необходимостью, с одной стороны, как можно более ясно отражать имеющиеся требования, сформулированные на естественном языке, и, с другой стороны, допускать возможность их переформулирования в другом стиле в ходе построения моделей, поскольку оно позволяет выявить неточности, рассогласования и неполноту в исходных требованиях и углубить их понимание [17].
- Средства для явного указания связей с документами, содержащими требования, и стандартами, если они относятся к проверяемой системе. Такие связи используются для прослеживания исходных требований и установления того, что все необходимые ограничения действительно присутствуют в модели, а лишних ограничений в ней нет. В дальнейшем они же позволяют проследить связи требований с полученными автоматически тестами.
- Возможность автоматического преобразования моделей в тестовые оракулы.
- Возможность использования структуры моделей для определения критериев тестового покрытия.
- Стоит поддерживать возможности использования таких моделей в рамках других техник верификации.
- Полезна также возможность преобразования модели поведения в однозначную и полную документацию на моделируемую систему. Однако способы реализации этой возможности остаются за рамками данной работы.
- Модели ситуаций.
- Средства для описания ситуаций, связанных с различными аспектами поведения и структуры тестируемой системы. На практике критерии полноты тестирования используют разнообразные свойства для характеризации ситуаций: структуру входных данных и результатов, внутренние состояния системы, выполняемые инструкции кода и вызываемые внутри функции, шаблоны передачи данных внутри системы, шаблоны взаимодействия различных частей системы при выполнении операции, характеристики ожидаемого поведения, возможные ошибки в системе и пр.
- Средства для явного указания связей определяемых классов ситуаций с исходными требованиями к системе.
- Возможность автоматического преобразования в компоненты, определяющие класс текущей ситуации, измеряющие достигнутое покрытие.
- Возможность автоматического извлечения из описания классов ситуаций ограничений на входные данные и состояние тестируемой системы или моделей ее поведения, чтобы можно было их использовать для нацеленного построения соответствующих тестов.
Как видно, требования к представлению моделей делятся на три типа: достаточная для практических целей выразительность, прослеживаемость к требованиям и возможность автоматического решения различных задач построения тестов.
Рассмотрим теперь имеющиеся инструменты тестирования с точки зрения их приближения к желаемому идеалу — инструментарию на основе компонентной технологии.
Важным классом инструментов тестирования, в большой степени обладающих свойствами модульности, являются средства модульного тестирования (unit testing) [5]. Наиболее известен из таких инструментов JUnit [6], написанный на Java и предназначенный для тестирования кода на этом языке, хотя исторически первым был SUnit [18,19] для программ на Smalltalk.
Для этих инструментов характерны высокая гибкость, возможность подключения совершенно независимых модулей для реализации дополнительных функций и возможность использования в рамках более сложных тестовых систем. Одним из инструментов модульного тестирования, обладающих наиболее богатой функциональностью, является TestNG [20,21]. Его основные характеристики таковы.
- Конфигурация тестов.
- Основные элементы тестов — тестовые классы и тестовые методы, описываемые как классы и методы языка Java, имеющие аннотацию @Test.
- Комплект тестов имеет иерархическую структуризацию: в нем выделяются тестовые наборы (test suites), состоящие из тестов (tests). Далее в этом списке характеристик эти термины используются только в узком, специфическом для TestNG смысле. Тесты и тестовые наборы определяются конфигурацией тестов, описываемой в некотором формате на базе XML. Тест составляется из методов нескольких классов, выбираемых либо на основе их имен, либо по принадлежности к группам, указываемым в аннотациях методов.
- Методы инициализации (set-up) и финализации (tear-down), используемые для инициализации некоторых данных перед выполнением тестов и освобождения занятых ресурсов после, могут быть определены для всех элементов иерархии: для наборов, тестов, классов и методов.
- Возможно определение зависимостей между тестовыми методами и между методами и группами, позволяющее управлять порядком их выполнения и отменять выполнение тестового метода, если один из тестовых методов, от которых он зависит, выполнился с ошибками.
- Тестовые данные и объекты.
- Тестовые методы в TestNG могут быть параметризованными. Набор значений параметров, используемый в рамках теста, указывается с помощью дополнительной аннотации или в конфигурационном файле и должен представляться либо в виде заданной коллекции объектов, либо как последовательность результатов, возвращаемых определенным методом при работе теста.
- Можно создавать фабрики объектов, строящие разнообразные объекты тестовых классов. Все входящие в тест методы выполняются для каждого такого объекта.
- Проверка результатов тестирования.
- Основной способ описания выполняемых тестовыми методами проверок, как и во многих других инструментах модульного тестирования — это использование библиотеки методов-утверждений. Каждый такой метод (обычно их названия начинаются с assert) проверяет простое свойство своих аргументов (равенство, неравенство null, вхождение символа в строку, вхождение объекта в коллекцию и пр.) и при его нарушении выдает трассировочное сообщение, также указываемое в виде аргумента.
- Дополнительно TestNG поддерживает указание возможных исключений и ограничений на время работы тестового метода в его аннотации.
Инструменты модульного тестирования активно используют развиваемые независимо модули для решения разных более специфичных задач. Например, dbUnit [22] — для организации работы с базами данных в модульных тестах используется, httpUnit [23] — для обработки HTTP-запросов. Для более наглядной записи выполняемых в тестах проверок (близкой к формулировкам естественных языков) можно применять библиотеки, предоставляемые инструментами разработки на основе функциональности (behavior driven development), например, JBehave [24] или NSpecify [25], для организации тестовых заглушек — библиотеки Mockito [26], EasyMock [27] и т.д.
Инструменты тестирования на основе моделей
Инструменты тестирования на основе моделей с точки зрения их приближения к желательной компонентной архитектуре можно разделить на три группы.
- Традиционные «монолитные» инструменты, использующие специфические языки для оформления моделей. Добавление новых компонентов в них может на практике осуществляться только их разработчиками, а их использование в рамках более широкого инструментария возможно, только если разработчики заранее позаботились о предоставлении подходящего набора интерфейсов.
К инструментам такого типа относятся практически все многочисленные исследовательские прототипные средства тестирования на основе моделей и ряд более стабильных инструментов, использовавшихся во многих разных проектах. В этой второй категории находятся TorX [28,29], TGV [30,31], BZ-TT [32] и Gotcha-TCBeans [33,34]. Все они основаны на моделировании проверяемой системы в виде различных автоматных моделей. На тех же принципах в целом построены и коммерческие инструменты Conformic Qtronic [35] и Smartesting Test Designer (ранее Leirios) [36].
- Инструменты на основе расширений широко используемых языков программирования, которые сохраняют «монолитность». Примерами являются поддерживающие технологию UniTESK [37-39] инструменты CTESK и JavaTESK, а также SpecExplorer [40,41], разрабатываемый в Microsoft Research. В обоих случаях для моделирования поведения тестируемых систем используется комбинация из автоматных моделей и контрактных спецификаций.
- Инструменты, использующие для оформления моделей обычные языки программирования и обладающие рядом характеристик модульности. В частности, эти характеристики включают возможности достаточно легкой интеграции с компонентами от независимых разработчиков и использования самих таких инструментов как части более широкого инструментария.
Такие инструменты начали появляться не так давно, около 4-5 лет назад. Два наиболее известных примера — это ModelJUnit [8,42] и NModel [43,44]. Похожий инструмент mbt.tigris.org [45] использует для описания моделей графическую нотацию, поэтому гораздо менее приспособлен для использования в рамках чужих разработок. Иного рода пример — недавно созданная в Microsoft Research библиотека для описания и контроля декларативных ограничений на поведение .NET компонентов CodeContracts [46,47].
Возможности инструментов последнего вида стоит рассмотреть подробнее.
ModelJUnit и NModel построены как расширения простых средств модульного тестирования. Они используют для построения тестов только модели поведения, модель ситуаций явно не задается, неявно разные критерии полноты закладываются в используемые для построения тестов алгоритмы. Модель поведения преобразуется в сопряженную модель теста, определяющую не само требуемое поведение, а способ его исследования и проверки.
- Модель теста описывается в виде расширенного конечного автомата, представленного на языке программирования (Java или C#) в виде тестового класса, как и в средствах модульного тестирования. Такой класс либо помечается с помощью некоторой аннотации (атрибута в C#), либо реализует определенный интерфейс. Элементы автоматной модели — состояния, переходы, охранные условия переходов — задаются с помощью методов и полей этого класса.
- Состояние в NModel задается набором значений полей тестового класса (можно определять поля, не включаемые в состояние, помечая их специальными атрибутом), а в ModelJUnit — результатом метода getState().
- Действия, в результате выполнения которых выполняются переходы в модели теста, представляются методами, помеченными определенной аннотацией (атрибутом). В NModel действия могут быть параметризованными, причем набор значений параметров, используемый в рамках теста, указывается с помощью дополнительной аннотации в виде коллекции объектов соответствующего типа.
- Действия могут иметь охранные условия, которые должны быть выполнены, чтобы можно было выполнять соответствующее действие. В обоих случаях охранные условия представлены как методы, имеющие имена, построенные из имени соответствующего метода-действия с некоторым постфиксом.
- NModel дополнительно имеет следующие возможности.
- Композиция нескольких моделей, в которых одноименные действия рассматриваются как выполняемые одновременно. Модели для композиции указываются инструменту построения тестов перечислением имен соответствующих классов.
- Проверка моделей (model checking). Свойства безопасности проверяются за счет анализа возможности нарушения инвариантов состояний, представленных как методы с особым атрибутом. Свойства живучести могут удостоверяться за счет анализа достижимости стабильных состояний, в которых специально отмеченные характеристические методы возвращают true.
Библиотека CodeContracts предоставляет средства для описания чисто декларативных ограничений на свойства входных параметров и результатов операций. Моделирование состояния не поддерживается. Имеются следующие возможности.
- Ограничения записываются на языке C# в виде булевских выражений, передаваемых как аргументы библиотечным методам.
- Можно описывать ограничения следующих видов.
- Предусловия операций (метод Contract.Requires).
- Постусловия операций при нормальной работе (Contract.Ensures).
- Постусловия операций при выдаче исключения (Contract.EnsuresOnThrow).
- Утверждения о выполнении некоторых свойств в какой-то точке кода внутри метода (Contract.Assert).
- Инварианты классов — оформляются в виде методов со специальной аннотацией, содержащих обращения к Contract.Invariant.
- Помимо обычных выражений на C# можно использовать следующие.
- Кванторные выражения, оформленные в виде обращений к методам Contract.Exists и Contract.ForAll.
- Обращение к значениям выражений до выполнения проверяемого метода в постусловиях в виде вызова метода Contract.OldValue.
- Обращение к значению результата в постусловиях с помощью Contract.Result.
- Библиотека CodeContracts дополняется двумя инструментами: для статической проверки сформулированных ограничений на основе дедуктивного анализа и для их динамической проверки при выполнении методов, ограничения к которым описаны.
Итоги обзора существующих инструментов
Из приведенного обзора видно, что компонентные средства тестирования на основе моделей в последние годы активно развиваются, однако пока не достигли необходимой функциональности, отставая по ряду возможностей от инструментов модульного тестирования. Необходимо дополнить имеющиеся наработки следующими возможностями.
- Явное определение модели поведения проверяемого компонента, отдельное от модели теста. Такое разделение необходимо, прежде всего, для поддержки точности и полноты моделирования. Не менее важно и многократное использование моделей, поскольку на основе одной модели поведения компонента могут быть построены разнообразные тесты, нацеленные на достижение различных целей, как для этого компонента, так и для содержащих его подсистем. Еще одна полезная возможность — использование таких моделей в рамках других техник верификации. Пример выделения модели поведения дает библиотека CodeContracts.
- Расширенные выразительные возможности для описания моделей поведения. В частности, нужно обеспечить возможность использования разных стилей моделирования и сочетания разнообразных методов и техник построения тестов, а также других методов верификации. Это требование является следствием сложности и разнообразия требований к современным программным компонентам [48,49]. Библиотека CodeContracts позволяет указывать только чистые декларативные ограничения, что существенно снижает возможности ее использования для большинства практически значимых систем, поведение которых зависит от внутренних состояний их компонентов.
- Явное определение моделей ситуаций для построения тестов. Неявное задание модели ситуаций в имеющихся сейчас инструментах ограничивает возможности использования различных критериев полноты тестирования и затрудняет их осознанный выбор разработчиками тестов.
- Средства явной привязки моделей к требованиям на естественном языке. Такие возможности, необходимые для прослеживания требований, имеются в инструментах CTESK и SpecExplorer. В средствах модульного тестирования так можно использовать текстовые сообщения в методах проверки утверждений, однако подобных возможностей лишены NModel и ModelJUnit. Отметим, что добавление такой функциональности в модульный инструмент не представляет большого труда.
- Совместное использование моделей поведения, ситуаций и тестов, связанных с различными аспектами функциональности одного компонента на основе неинвазивной композиции. За счет этого можно существенно облегчить многократное использование моделей в тестировании и других техниках верификации. NModel частично решает эту задачу для моделей тестов за счет использования возможности расширять определения классов новыми полями и методами в C#.
Назад Содержание Вперёд
|
|