Тестирование на основе моделей

реклама
Тестирование на
основе моделей
к.ф.-м.н. В. В. Кулямин
ИСП РАН
Тестирование вообще
Тестирование (IEEE 610, SWEBOK):
Оценка соответствия системы требованиям к ней
на основе результатов наблюдения за ее работой
в специально подготовленных ситуациях




Система в ходе тестирования должна работать
Нужно готовить специальные ситуации – тесты
Оценивается соответствие – ищем ошибки
Нужна общая оценка – ищем все ошибки
«Обычное» тестирование
1.
2.
3.
4.
5.
Придумываем ситуацию
Оформляем ее в виде сценария взаимодействия
теста с системой
Понимаем, как должна система вести себя в его
рамках
Дополняем сценарий проверкой правильности
Результат – тестовый вариант (test case)
Оцениваем достаточность имеющегося набора
ситуаций: достаточно – конец, нет – goto 1
«Обычное» тестирование
Ограниченная очередь размера 3
1. В начале – пуста
1. В начале – полна
2. put(X)
2. put(X)
3. Y = take()
3. assert (exception)
4. assert (Y == X)
?
Зачем здесь модели?

Распознавание ошибки
– ментальная модель правильной работы
Math.abs(-2147483648) = -2147483648

Полнота набора ситуаций
– ментальная модель всех важных ситуаций
При тестировании на основе моделей
модели выделяются явно и заранее
Используемые модели
Конечные автоматы
(Finite State Machines, FSM)
 Программные контракты
(Software Contracts)
 ...

Конечный автомат (банкомат)
Начало
Время / Вывести
исходное сообщение
Время / Вывести
исходное сообщение
Карта / Вывести
приглашение ввести PIN
Сообщение о
выдаче баланса
Сообщение о
блокировке
Запрос баланса /
Выдать чек
Авторизация
Некорректный PIN
/ Сообщение
Корректный PIN /
Авторизация 1
Вывести меню
Некорректный PIN /
Заблокировать карту
Некорректный PIN
/ Сообщение
Авторизация 2
Выбор
операции
Сообщение о
выдаче денег
Сумма / Выдать
деньги
Выбор
суммы
Запрос денег / Вывести
вопрос о сумме
Тестирование на основе FSM
a/x
0
b/y
a/x
1
b/x
a/x
b/y
b/y
a/x
2
1
a/y
0
b/x
b/y
2
a/y
Модель


Реализация
Можно ли проверить, ведет ли себя неизвестная
реализация всегда так же, как модель?
При каких условиях это можно сделать?
Проверка соответствия

Требования к модели




Полная определенность
Минимальность
Сильная связность
b/y
Гипотезы о реализации




0
b/y
Реализация – конечный автомат с
теми же стимулами и реакциями
Полная определенность
В начале находимся в начальном
состоянии
Число состояний ограничено
a/x a/x
0b/y b/y
a/x
a/x
1 1a/y
0
b/x
a/x
b/y
1a/x
=2
0
a/y
b/y
a, b
0
1
3
2
x, y
Методы проверки – обход
Построение обхода
(transition tour)
aababb
s = status – возвращает
идентификатор состояния
sasasbsasbsbs
 0x1x1x2y2y0y2 (xxxyyy)
 0x1x1x2y2y1x2 (xxxyyx)
 0x1x1x2y2y2y2 (xxxyyy)
a/x
0
b/y
a/x
1
a/x
b/x
b/y
2
a/y
0
b/y
a/x
1
b/x
2
a/y
b/y
a/x
0
b/y
b/y
a/x
1
b/x
2
a/y
Методы проверки – W-метод
0
r = reset – переводит в начальное состояние
a/x
b/y
S – множество последовательностей, достигающих
b/y
a/x
всех состояний
1
2
S = {ε, a, b}
b/x
a/y
W – множество последовательностей,
reset
различающих все состояния
W = {a, b} – 0:{x, y}; 1:{x, x}; 2:{y, y}
S{a,b}W – полный тест
{ε, a, b}{a, b}{a, b} = {aa, ab, ba, bb, aaa, aab, aba,
0
abb, baa, bab, bba, bbb}
1
0
3
aarabrbarbbraaaraabrabarabbrbaarbabrbbarbbb
a/x
b/y
 xx.xx.yy.yy.xxx.xxx.xxy.xxy.yyy.yyy.yyx.yyy
b/y
2
a/x
 xx.xx.yy.yy.xxx.xxx.xxy.xxy.yyy.yyy.yyy.yyy
1
2
b/x
S{a,b}m-nW
– полный тест для больших реализаций
a/y
Другие методы проверки



D-метод
различающая последовательность
u = ba – 0:yy; 1:xy; 2:yx
S{a,b}u
abarbbaraabarabbarbabarbbba
Методы, работающие без reset
Адаптивные методы
a/x
0
b/y
a/x
1
b/x
b/y
2
a/y
Получаемые тесты



abarbbaraabarabbarbabarbbba 
xxy.yyx.xxxy.xxyx.yyyx.yyyy
z = a(); assert(z == ‘x’);
z = b(); assert(z == ‘x’);
z = a(); assert(z == ‘y’); reset();
…
Тесты теперь можно генерировать полностью
автоматически, если выполнены все
ограничения на модель
Конечные автоматы – еще не все





Не всякую задачу удобно описывать
конечным автоматом
Часто можно только очень большим
Сложность построения тестов O(p(m-n+1)n3)
Чаще всего ограничения на число состояний
в реализации неизвестны
Часто требования недетерминированы
Часто результат в некотором состоянии
определен не для всех стимулов
Конечные автоматы – еще не все
Ограниченная очередь размера 3
[X, X, X]
[X, X]
[X, X, Y]
[Y, X, X]
[X]
[X, Y]
[X, Y, X]

[Y, X, Y]
[Y, X]
[Y]
[X, Y, Y]
[Y, Y]
[Y, Y, X]
[Y, Y, Y]
Конечные автоматы – еще не все
Система управления памятью
void* malloc(int n)
void free(void* m)
malloc(3); malloc(5); malloc(4); malloc(7); malloc(7);
Конечные автоматы – еще не все
Таймер
выключить
включить
сигнал
init(3)
Барьер
wait()
wait()
wait()
Высота 3
Программные контракты



Система –
набор взаимодействующих компонентов
Компоненты взаимодействуют с помощью
вызовов интерфейсных операций друг друга
Каждая операция имеет
 Предусловие
Определяет, когда операцию можно вызывать
 Постусловие
Описывает результаты работы операции
Пример контракта
Вычисление целочисленного логарифма
int logn(int x, int b)
pre
(b > 1) & (x > 0)
post
blogn ≤ x & blogn+1 > x
Что это дает для тестирования?

Можно тестировать





Постусловие дает критерий правильности
Тест можно разбить на два компонента



отдельные компоненты
большие подсистемы
систему в целом
Генератор тестовых данных
Оракул – проверяет правильность работы на любых данных
Можно записывать сложные и недетерминированные
ограничения
Более сложный пример
АРМ компоновщика заказов
 Показывает список заказов для обработки
 Позволяет
 Добавить
новый заказ в конец списка
 Добавить срочный заказ в конец подсписка
срочных заказов
 Пометить заказ как срочный
 Убрать первый заказ из списка (когда он
обработан)
Контракт добавления заказов
List urgent;
List ordinary;
int MAX;
boolean addOrdinary(Order o) {
pre { return true; }
post {
if(@ordinary.size + @urgent.size < MAX)
return
ordinary
== @( ordinary.add(o) )
&& urgent
== @urgent
&& addOrdinary == true ;
else
return
ordinary
== @ordinary
&& urgent
== @urgent
&& addOrdinary == false ;
}
}
Контракт переноса заказа в срочные
boolean moveToUrgent(Order o) {
pre { return true; }
post {
if(@( o in ordinary ))
return
ordinary
==
&& urgent
==
&& moveToUrgent ==
else
return
ordinary
==
&& urgent
==
&& moveToUrgent ==
}
}
@( ordinary.remove(o) )
@( urgent.add(o) )
true ;
@ordinary
@urgent
false ;
Контракт удаления заказа
Order removeFirst() {
pre {
return urgent.size != 0
}
post {
if(urgent.size != 0)
return
ordinary
&& urgent
&& removeFirst
else
return
ordinary
&& urgent
&& removeFirst
}
}
|| ordinary.size != 0 ;
== @ordinary
== @( urgent.removeFirst() )
== @( urgent[0] ) ;
== @( ordinary.removeFirst() )
== @urgent
== @( ordinary[0] ) ;
Что получилось?
true / false
Тестируемая система
Оракул
Модель
Что еще надо?

Проверка правильности
+

Построение тестовых данных
?

Оценка полноты набора тестов
?
Полнота тестов
Покрытие кода тестируемых функций
 Метод функциональных диаграмм

Покрытие постусловия
post {
if
( a <= 0 || c.isActive() )
else if( a > 3 & !b.closed() )
…
else
…
a > 0 && !c.isActive() && a <= 3
|| a > 0 && !c.isActive() && b.closed()
}
…
Покрытия контракта и кода
Постусловие


Код
Если покрытие постусловия выше, то покрытие кода
выше
100% постусловия и 100% кода не следуют друг из
друга
Метод функциональных диаграмм
+: int × int → int
int = {positive, 0, negative}
Первый аргумент
Второй аргумент
Пример
pos
pos
2, 3
pos
0
2, 0
pos
neg
2, -1
0
pos
0, 3
0
0
0, 0
0
neg
0, -1
neg
pos
-2, 3
neg
0
-2, 0
neg
neg
-2, -1
Метод функциональных диаграмм
if(a > 0 && F(b) < 5)
returna f
> 0== g(a)-F(b)*b && a == @a + 1;
f == g(a)-F(b)*b
else if(isActive(c))
return f == -1 && a == @a;
a == @a + 1
else
F(b) < 5
return f == 0 && a == @a;
f == -1
isActive(c)
a == @a
f == 0
Пример – ветви постусловий




addOrdinary()
 ordinary.size + urgent.size
 ordinary.size + urgent.size
addUrgent()
 ordinary.size + urgent.size
 ordinary.size + urgent.size
moveToUrgent(o)
 ( o in ordinary )
 !( o in ordinary )
removeFirst ()
 urgent.size
!= 0
 ordinary.size != 0
< MAX
== MAX
adOrN
adOrE
< MAX
== MAX
adUrN
adUrE
mvN
mvE
rmUr
rmOr
Обобщение состояний, шаг 1
Условия
Состояние adOr
adUr
mv
rm
(0, 0)
A
B
D
A
-
(0, 0 < o < M)
B
B, C
E, F
E
A, B
(0, M)
C
C
C
F
B
(0 < u < M, 0)
D
E, F
D, G
D
A, D
(u, o) u+o < M E
E, F
E, F
E
B, E
(u, o) u+o = M F
F
F
F
B, E
(M,0)
G
G
G
E
G
Обобщение состояний, шаг 2
urgent.size
addOrN
MAX
addUrN
addOrE, addUrE
mvN
mvE
rmUr
0
rmOr
0
MAX
ordinary.size
Редукция сложных автоматов
Итоги

Программные контракты
Оракул
  Ветви постусловий – важные ситуации

Построить обход переходов
обобщенного автомата
 Подготовить тестовые данные (?)

В чем цель тестирования?
(Дейкстра)
Тестирование не может подтвердить
правильность, но может найти ошибки
 => (?)
Цель тестирования – поиск ошибок
 <=
Тестирование, не находящее ошибок –
бесполезно

В чем цель тестирования?


А как бы мы иначе узнали, что ошибок в программе
нет?
Тестирование – это метод оценки качества системы



Если ошибки есть, оно их должно находить
Если их нет, оно должно это подтверждать
Оно должно давать еще много информации




Какие части системы наиболее устойчивы
Где, вероятно, еще есть ошибки и какого рода
Достаточно ли высоко качество системы в целом и стоит ли
тратить усилия на доработку
Модели – способ сделать эту оценку более надежной
и объективной
Скачать