Методы формальных спецификаций программ

advertisement
??.02.2004 (?)
Зимний семестр. Лекция 1.
Методы формальных спецификаций программ.
Тема называется «Методы автоматизации тестирования».
Тесты – тоже программы, только специального вида. И подходить к их разработке
мы будем с точки зрения разработки обычных программ.
Этапы разработки программ:
1. Анализ предметной области – чтобы вообще понять, о чем говорит заказчик
2. Анализ требований – чтобы собственно сформулировать требования заказчика
3. Разработка внешних спецификаций – требования явно, четко и недвусмысленно
выписываются (с возможностью находить противоречия и несогласованности; до
формализации доходит редко). Требования говорят о том, какие задачи должна
решать система. Решение каждой задачи разбивается на решение ряда подзадач.
Для каждой подзадачи определяется набор требуемых компонент.
4. Разработка архитектуры системы (система разбивается на модули в
соответствии функциями; каждый модуль отвечает за решение отдельной
подзадачи)
a. Разработка спецификаций модулей (интерфейсы взаимодействия между
компонентами)
5. Кодирование
6. Тестирование и отладка. А почему тестировать можно начинать только сейчас?
Почему нельзя тестировать, например, архитектуру системы? Проверить-то на
соответствие можно, но в тестирование входит еще и выполнение тестируемой
программы. Мы фиксируем способ проверки на соответствие – путем запусков
программы. Разработка тестов выделяется отдельно. По результатам наблюдений
проверяется соответствие требованиям. В чем разница между тестированием
отдельной компоненты и тестированием всей программы? Люди, тестирующие
систему, тестируют уже готовый продукт и могут не обладать знаниями о его
внутреннем устройстве. Выделяют следующие этапы тестирования:
a. Тестирование модулей (тестируется отдельный небольшой модуль)
b. Интеграционное тестирование (тестируется правильность взаимодействия
модулей друг с другом)
c. Системное тестирование (тестируется система в целом)
7. Сопровождение ПО.
Попытаемся эти же шаги применить к тестам как к программам
специального вида:
1. Анализ предметной области.
2. Анализ требований. Полнота тестового покрытия – должны покрываться по
возможности наиболее широкие классы входных данных. На целевую программу
можно оказывать воздействия, в ответ получать реакции.
a. Достаточная полнота тестирования. Мы должны определить, насколько
полно они должны тестировать нашу систему.
i. Ошибки обработки входных данных. Здесь могут быть ошибки с
неправильным разбиением входных данных или с ошибками на
граничных условиях. На этом основаны:
1. Техники тестирования доменов (Partition testing). Есть
входной тип – целые числа. При этом для чисел больших 1
функция должна делать одно, при меньших -3 – другое, при
прочих – третье. Мы выбираем представителей каждой из
групп и граничные значения. Модель покрытия – покрытие
доменов.
2. Синтаксическое тестирование. Если возникает некоторых
формальный язык (язык общения по сети, формат входных
файлов), можно строить воздействия в соответствии с
правилами грамматики этого языка. Можно выделить два
момента: порождение правильных данных и порождение
неправильных данных (о последнем часто забывают).
Модель покрытия – различные синтаксические конструкции.
ii. Ошибки «в коде» - связаны с потоками управления и потоками
данных, а также другими моментами:
1. Потоки управления – написали ошибочное условие или
написали один знак «равно» вместо двух. Модель покрытия покрытие потоков управления.
2. Потоки данных – например, в цикле ищется вхождение
подстроки в строку. Если мы где-то в цикле написали
лишнюю единицу, то дальнейшее управление может пойти не
так. Сюда попадают ошибки, связанные с инициализацией
одной переменной через другую. Модель покрытия покрытие потоков данных.
3. Переход управления между компонентами – например,
забыли написать проверку входных данных. Модель покрытия
- покрытие переходов состояний.
iii. Ошибки при реализации требований. Требования реализованы не
полностью – например, что-то забыли или не успели реализовать
(или намеренно не реализовали). Модель покрытия – покрытие
требований.
iv. Ошибки в обработке истории взаимодействия с окружением.
Можно, если программу представить в виде автомата, понимать это
как переход в неправильное состояние или отсутствие какой-то
операции. Модель покрытия – покрытие состояний или переходов
(Адинец А.В.)
v. Ошибки синхронизации параллельно работающих процессов.
Предпринимаются попытки определить какую-то модель покрытия в
этой области, пишутся по этому поводу статьи, но общепризнанной
модели покрытия пока нет.
b. Проверка требований к тестируемой системе. Раз мы проверяем
требования к системе, то мы их должны знать. И наши тесты должны их
проверять. Рассмотрим, кто или что может проверять требования и как их
можно проверять:
i. Тестировщик – мы просто смотрим на то, какие результаты
получились. Используется довольно часто.
ii. Вообще ничего не проверять – смотреть только, упала программа
или нет. Используется при тестировании устойчивости.
iii. Формальное описание поведения. Здесь может быть несколько
форм описания поведения:
1. Операционная спецификация (или явная) – описывается,
какие действия выполняется и какой результат должен быть
получен
2. Аксиоматическая спецификация – в виде аксиом.
Например, запихнув объект в стек, а потом достав его оттуда,
мы не изменим состояние стека.
3. Сценарное – как набор сценариев работы системы. Например,
если мы подадим на вход что-то, то получим то-то и то-то, а
по сети будет передано что-то еще. Можно для целей
описания сценариев использовать темпоральные логики и
описывать свойства, которые должны быть выполнены в
определенный момент.
4. Контрактная спецификация – пред- и постусловия на
входные и выходные данные, инварианты целостности
данных.
c. Отчеты о том, как тесты работали, что они тестировали, насколько успешно
прошло тестирование, где произошла ошибка. Это вещь достаточно
техническая, особо ее касаться мы не будем.
Дальнейшая разработка будет сильно зависеть от того, как мы решим эти 3 задачи.
Как можно, например, проверять на соответствие требованиям?
Поговорим теперь о полноте тестирования. Что под этим понимается? Например,
каждый оператор должен быть выполнен хотя бы один раз. Или полнота покрытия
различных классов входных данных. Полнота покрытия типов – мы нигде не забыли
обработать некоторые специфические типы. Полнота покрытия разных веточек говорит о
выполнении каждой веточки кода определенное количество раз. Если есть ошибка в
каком-то операторе, то, может быть, мы ее при тестировании найдем. Составляя тесты, мы
исходим из того, какие ошибки наиболее часто совершаются. И именно по этой
информации мы определяем, насколько тесты полны.
Зачастую требуется определять полноту покрытия количественно. Тогда
используется понятие модели покрытия. С каждым типом ошибок связан определенный
тип покрытия.
А теперь нужно определить, как строить тесты. Пусть есть тестируемая программа
и тестирующая программа. Тестовые данные необходимо генерировать.
Тестирующая программа
Генератор данных
Оракул (проверяет
правильность реакции)
Тестируемая
программа
Генерация отчетов
Данные нельзя генерировать бесцельно. Нужно вызывать определенные функции в
определенные моменты, нужно вести историю входных данных. Нужно иметь:
1. Генератор воздействий – генерирует действия, которые мы бы хотели получить.
2. Генератор данных очередного воздействия – генерирует данные для каждого из
воздействий, например, координаты щелчка мыши.
А каким образом можно генерировать входные данные?
1. Вероятностная генерация – генерация случайных данных. Используется довольно
часто, и может обеспечить нормальное покрытие. Достаточно просто. Особенно
для тестирования небольших процедур.
2. Комбинаторная генерация – выделяются различные аспекты взаимодействия
(принтер включен или выключен, разные ОС, разные документы), после этого
представители различных классов комбинируются.
3. Автоматная генерация – использование автоматных моделей (в том числе
простейших) для генерации тестов. Пусть имеется терминальный автомат. Можно
поставить за цель побывать при тестировании во всех состояниях автомата. Можно
пытаться покрыть все переходы. Тесты – этого различного рода пути на этом
автомате. Схема автомата – это схема тестируемой программы.
4. Переписывание термов. Есть, например, аксиоматическое описание стека.
Например, последовательность push(a), pop() не изменяет состояние стека. Если
вставить ее в какую-то другую последовательность, то мы должны получить
эквивалентную
последовательность.
Можно
проверять
измененные
последовательности на эквивалентность.
Вероятностное тестирование применяется в 2-х случаях:
1. Ничего не понятно.
2. Формулирование тестов в соответствии с Марковскими процессами. Например,
рассматривается вероятность или риски тех или иных ошибок, и наиболее опасные
ошибки протестировать наиболее тщательно.
Комбинаторная генерация – один из самых простых способов. Для него не нужно
практически ничего.
Есть две основные методики тестирования: белый ящик и черный ящик. При
тестировании белым ящиком мы используем как требования, так и внутреннюю структуру
программы. При использовании черного ящика мы можем рассматривать только описание
системы. Серый ящик (различная степень серости) – когда у нас есть доступ только к
части структуры системы.
На следующих лекциях будет рассматриваться система UniTesK и то, что она
предлагает для тестирования. Эта система основана на формальных спецификациях.
Основным видом спецификации является контракт, хотя аксиомы тоже могут
использоваться, хоть и менее эффективно. Для оценки качества тестирования
используется покрытие спецификаций. Покрытие измеряется исходя из кода
спецификации – сколько единиц спецификации покрыто. Для построения
последовательности тестирования используется автоматная модель, а для построения
отдельных взаимодействий – комбинаторная модель. Используемый метод тестирования –
черный ящик. Иногда, если есть надежные методы чтения состояния системы,
используется тестирование с открытым состоянием.
Download