https://github.com/nikiforovta/software-testing-exam
Вопросы к экзамену по курсу "Тестирование ПО"
https://github.com/nikiforovta/software-testing-exam
Last synced: 2 months ago
JSON representation
Вопросы к экзамену по курсу "Тестирование ПО"
- Host: GitHub
- URL: https://github.com/nikiforovta/software-testing-exam
- Owner: nikiforovta
- Created: 2022-04-21T07:07:07.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2022-04-21T10:00:39.000Z (about 3 years ago)
- Last Synced: 2025-01-16T16:59:26.570Z (4 months ago)
- Homepage:
- Size: 34.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 1. Тестирование ПО: основы
Функциональные требования:
- адекватность
- точность
- интероперабельность
- безопасностьНефункциональные требования:
- надежность
- эффективность
- поддерживаемость
- переносимостьТестирование ПО занимает до 80% времени при разработке программного обеспечения.
В основе тестирования ПО лежит вопрос "Работает ли это ПО неправильно?" вместо "Работает ли это ПО правильно?".
Тестирование = Разрушение.Тестирование - лучший друг верификации и валидации ПО.
**Верификация** - "мы сделали это правильно"
**Валидация** - "мы сделали то, что надо"
Стоимость устранения ошибки растет на последующих этапах разработки ПО экспоненциально, поэтому чем раньше будет
устранена ошибка, тем лучше.# 2. Модель программной ошибки. Модель тестирования ПО и место тестирования в процессе разработки ПО.
Модель программной ошибки - треугольник из трех частей: неудача, сбой и ошибка.
**Неудача** - наблюдаемое **снаружи** некорректное поведение программы
**Сбой** - некорректное состояние программы из-за ошибки
**Ошибка** - шибка в самой программе, внесенная на этапе разработкиМодель тестирования ПО состоит из ПО, эталонной модели, тестового оракула и результатов тестирования. Эталонная модель
может быть представлена множеством способов:* неформальное представление о том, "как должна работать программа"
* формальная техническая спецификация
* набор тестовых примеров
* корректные результаты работы программы
* другая (априори корректная) реализация той же исходной спецификацииВозможные исходы в модели тестирования ПО: тест прошел (отлично), тест не прошел (ошибка в ПО, ошибка в эталонной
модели, ошибка в тестовом окружении, ошибка в платформе).Чем активнее используется тестирование в процессе разработки, тем важнее его правильное использование. В водопадной
модели: тестирование выполняется над всей программой сразу, имеется хорошая эталонная модель, стоимость поиска и
исправления ошибок очень высока. В инкрементальной модели: разработка проходит в несколько итераций, тестируются
отдельные версии программы, имеется неплохая эталонная модель, стоимость поиска и исправления ошибок высока. В гибкой
модели: все этапы разработки неразрывно связаны друг с другом, тестированию подвергаются как сама программа, так и ее
компоненты, эталонная модель есть не всегда, стоимость поиска и исправления ошибок относительно низка.# 3. Проблема тестовых входных данных
`Как подобрать входные данные, чтобы:`
* `дойти до места с программной ошибкой `**`(Reachibility)`**
* `испортить состояние программы с появлением сбоя `**`(Corruption)`**
* `вызвать неудачу в работе программы `**`(Propagation)`**Способы управления выполнением кода: изменение входных данных, изменение самого исходного кода.
Входные данные: файлы, фактические аргументы функций, сетевые пакеты, результаты запроса к БД, последовательность
вызовов функций, конфигурация ПО.Классы эквивалентности - разбиение пространства входных состояний на подпространства, каждое из которых обрабатывается
тестируемым модулем одинаково с точки зрения спецификации. Тестирование всех классов эквивалентности позволяет найти
ошибки прямого нарушения спецификации. Ad hoc - тестирование методом "научного тыка". Запускаем ПО и смотрим на
результаты работы. Метод свободного поиска = Ad hoc testing + планирование. Описываем тест план и проверяем ПО на
соответствие ему. Анализ граничных значений - находим пограничные значения входных данных и проверяем ПО вокруг
выбранных пограничных значений.# 4. Проблема неявных входных данных
`В большинстве случаев спецификация не покрывает все множество входных данных. Проблема заключается в том, что на тестовый модуль, кроме явных, влияет множество `**`неявных`**` входных данных, которые часто не находят отражения в спецификации.`
Примеры неявных входных данных: текущая дата/время, IP/MAC адрес, локаль пользователя, идентификаторы устройств,
контекстные переключения/планирование нитей, скорость поступления IP пакетов, ритм нажатия клавиш на клавиатуре.Замена части модуля управляемыми заглушками позволяет сделать неявные входные данные явными, а также делает управление
явными входными данными проще. Использование заглушек позволяет имитировать возникновение редких ситуаций, внести
детерминизм там, где его нет. Mock-объекты повторяют внешний интерфейс тестируемого объекта и могут демонстрировать
любое требуемое поведение.Dummies - объект-муляж, не обладающий собственным поведением.
Fakes - упрощенная реализация требуемой функциональности.
Stubs - тестовая заглушка, способная отвечать на внешние запросы.
Mocks - тестовая заглушка, способная отвечать на внешние запросы и проверять их корректность.
# 5. Разработка через тестирование
Mock-объекты в процессе разработки используются для управления явными и неявными входными данными.
Test-driven development - пишем тест для компонента перед его разработкой, заменяем сам компонент заглушкой. Плюсы:
* Разработка ведется небольшими контролируемыми фрагментами (в каждый момент времени разработчик думает об ограниченном
фрагменте спецификации; это упрощает анализ возможного пространства входных данных; кроме того, код получается более
модульным и расширяемым)
* Минимальная цена ошибки (в случае возникновения ошибки очень просто вернуть систему в рабочее состояние; практически
отсутствует необходимость в отладке; крайне просто использовать метод бисекции в случае, если ошибка смогла пробраться
в релиз)
* Ошибки обнаруживаются сразу же после их появления (постоянный запуск тестов гарантирует практически моментальное
обнаружение ошибки; малый размер тестов позволяет быстро найти причину ошибки)
* Сильно упрощается рефакторинг кода (программист уверен в том, что его изменения ничего не ломают; облегчается
раздельное владение кодом)Минусы:
* Синдром "розовых очков" (большое количество тестов создает иллюзию бесконечной надежности системы тестирования; при
создании теста разработчик может сделать те же допущения, что и при разработке самого компонента)
* Поддержание тестов в актуальном состоянии (при внесении изменений в интерфейсы компонентов системы необходимо
соответствующим образом изменить и все тесты; Большое количество тестов приводит к значительным затратам на
рефакторинг тестов)
* Невозможность тестирования сложного взаимодействия нескольких компонентов (каждый тест проверяет ограниченный фрагмент
функциональности системы; взаимодействие компонентов затрагивает множество аспектов системы сразу)# 6. Интеграционное тестирование
Инкрементальное интеграционное тестирование производится при инкрементальной замене заглушек на реализацию.
Нисходящее интеграционное тестирование: начинается с верхних уровней системы, отсутствующие на данный момент модули
заменяются "заглушками", по мере реализации новых модулей они подключаются к системе вместо "заглушек". Преимущества:* Возможность ранней проверки корректности высокоуровневого поведения
* Модули могут добавляться по одному, независимо друг от друга
* Не требуется разработка множества драйверов
* Можно разрабатывать систему как в глубину, так и в ширину Недостатки:
* Отложенная проверка низкоуровневого поведения
* Требуется разработка "заглушек"
* Крайне сложно корректно сформулировать требования ко входам/выходам частичной системыВосходящее интеграционное тестирование: начинается с нижних уровней системы, отсутствующие на данный момент модули
заменяются драйверами, при реализации всех модулей нижнего уровня драйвер может быть заменен на соответствующий модуль.
Преимущества:* Возможность ранней проверки корректности низкоуровневого поведения
* Не требуется написание заглушек
* Просто определить требования ко входам/выходам модулей Недостатки:
* Отложенная проверка высокоуровневого поведения
* Требуется разработка драйверов
* При замене драйвера на модуль высокого уровня может произойти "мини-Большой Взрыв"Bonus:
`Для того, чтобы обеспечить порчу внутреннего состояния (corruption), необходимо:`
* `обеспечить достижимость`
* `передать такие тестовые входные данные, которые вызывают нарушение целостности внутреннего состояния`# 7. Проблема наблюдаемости. Ассерты.
`Необходимо обнаружить сбой и распространить его, сделав наблюдаемым снаружи (`**`Propagation`**`)`
Основной способ обеспечения наблюдаемости - assertions - формула в логике первого порядка. Проверяется на истинность во
время выполнения программы. Также может проверяться на истинность статически. Допускает возможность отключения проверки
истинности. Применение:* Проверка корректности внутреннего состояния (внутреннее состояние обычно недоступно снаружи (полностью или частично),
при изменении состояния хочется проверить, что оно остается корректным)
* Неудача происходит ближе к причине ее возникновения (чем больше задержка перед обнаружением неудачи, тем сложнее найти
ее исходную причину, assertions позволяют найти неудачу практически в любой точке программы)
* Явное документирование пред- и пост-условий (в общем случае программист ничего не знает о контракте используемой
функции, использование assertions позволяет в явном виде описать внешний контракт функции)
Проблемы:
* Ошибки в assertions (побочные эффекты в assertions, неправильное логическое условие срабатывания)
* Влияние на производительность (проверка assertions занимает время, чем сложнее assertion, тем больше он замедляет
работу программы)
* Эффект "вышибалы" (сработавший assertion превращает любую ошибку в неудачу, это полностью останавливает возможность
дальнейшего тестирования)
* Сложность проверки определенных условий (некоторые просто формулируемые условия крайне сложно проверить на практике,
их реализация в виде assertion является крайне затруднительной)# 8. Проблема наблюдаемости. Журналирование.
Журналирование (logging) - запись хода выполнения программы в том или ином виде. В зависимости от необходимости журнал
может быть более или менее детализированным. По журналу выполнения при необходимости возможно восстановить причину
возникшей ошибки.- Для пользователя: высокоуровневые сообщения; как можно меньше "мусора"; чем проще и понятнее формат сообщений, тем
лучше.
- Для программиста: низкоуровневые сообщения; допустим любой шум; никаких ограничений на формат сообщений.Основная проблема журналирования: чем больше мы хотим узнать о ходе выполнения программы, тем больше мы должны
журналировать -> чем больше мы журналируем, тем сложнее разобраться в журнале -> чем сложнее разобраться в журнале, тем
меньше мы знаем о ходе выполнения программы. Необходимо ограничивать размер записываемых данных.Сообщения пишутся в журнал с определенным уровнем (Error / Warning / Info / Debug / Trace), по которым в дальнейшем
сообщения можно фильтровать.Домены ортогональны уровням журналирования, в зависимости от типа сообщения пишутся в разные домены (Database / Network
/ UI / Configuration / …).Стохастическое журналирование - в случае, если какие-то события встречаются очень часто, достаточно записывать лишь их
часть. Сессионное журналирование - часто работа ПО разбита на набор слабо связанных сессий, каждая сессия может
журналироваться независимо от других.Структурированное журналирование - вместо простого текста журнал ведется в определенном формате, структурированный
формат облегчает поиск и анализ по журналу.# 9. Полнота тестирования ПО. Тестовое покрытие.
```
Проблема "останова" в тестировании:
По заданному набору тестов и программе определить, протестировали ли мы ее достаточно хорошо. Что такое "достаточно хорошо"?
```Качество тестирования можно оценить через тестовое покрытие. Выделяют два основных вида покрытия:
* Покрытие потока управления (по узлам, по дугам, по условиям, по путям графа потока управления (CFG))
* Покрытие потока данных (граф потока данных (DFG))### Покрытие потока управления
* Покрытие операторов программы - Каждый узел CFG был пройден в процессе тестирования хотя бы один раз; самый слабый
способ оценки тестового покрытия.* Покрытие ветвлений программы - каждая ветка программы была пройдена хотя бы один раз; несколько более сильный способ
оценки покрытия. Покрытие ветвлений не включает в себя покрытие операторов, потому что в программе могут отсутствовать
ветвления или может присутствовать "мертвый код".
* Покрытие условий программы - каждое ветвление может выполняться по различным причинам, при покрытии условий программы
мы требуем, чтобы все условия ветвлений хотя бы один раз приняли значение true и false.
* Модифицированное покрытие ветвлений и условий (MC/DC) - одно из обязательных условий при тестировании ПО на уровень A
в рамках DO-178B, каждое условие независимо повлияло на выполнение программы. Для проверки необходимо изменить
**одно** условие и проверить, изменилось ли ветвление.
* Полное покрытие условий программы - полный перебор всех возможных **комбинаций** условий всех возможных ветвлений.
* Покрытие путей программы - мы требуем, чтобы все возможные пути программы были выполнены хотя бы один раз. Обычно
считается самым сильным типом покрытия потока управления, и его можно было бы использовать, если бы не циклы и
рекурсия. Для борьбы с этим используют несколько подходов (например, требуем, чтобы тело цикла было выполнено `0`, `1`
, `k`, `max` раз).### Покрытие потока данных
Можно вспомнить о том, что программы работают не просто так, основная цель работы любой программы — работа с данными. С
этой точки зрения для тестирования представляет интерес анализ таких путей выполнения программы, на которых активно
работают с данными.Определение переменной (Def) - оператор программы, в котором значение переменной может быть изменено.
Использование переменной (Use) - оператор программы, в котором значение переменной влияет на выполнение программы тем
или иным способом.Def-Use Chain - пара (d, u) операторов программы, для которой выполняются следующие условия: d — определение переменной,
u — использование переменной, между d и u существует хотя бы один путь, на котором переменная не переопределяется.* Покрытие всех определений (All-Def Coverage) - для каждой интересующей нас переменной должна быть протестирована хотя
бы одна Def-Use Chain от **каждого** определения до хотя бы одного использования.
* Покрытие всех использований (All-Use Coverage) - для каждой интересующей нас переменной должна быть протестирована
хотя бы одна Def-Use Chain от **каждого** определения до **каждого** использования.
* Покрытие всех Def-Use Chain (All-Def-Use-Chain) - для каждой интересующей нас переменной v должны быть протестированы
все возможные Def-Use Chain от **каждого**
определения до **каждого** использования.# 10. Мутационное тестирование
Идеальный тест работает только на тестируемой программе, при любом изменении он перестает проходить.
Мутационное тестирование: исходная программа подвергается мутации, в результате получается набор из N мутантов, после
этого имеющиеся тесты запускаются на этих мутантах, если тест не проходит на мутанте, то говорят, что тест "убивает"
этого мутанта, доля "убитых" мутантов показывает, насколько полно данный набор тестов покрывает нашу программу. Для
создания мутанта необходимо провести набор синтаксических трансформаций, изменяющих исходный код (добавить новый код,
удалить старый, изменить существующий код). Некоторые мутанты будут синтаксически некорректны, другие мутанты будут
семантически некорректны, оставшиеся мутанты подходят для использования в мутационном тестировании.Недостатки:
* Практически невозможно выполнять вручную (количество необходимых для оценки покрытия мутантов пропорционально объему
анализируемого ПО; даже для небольшой программы получение достаточного числа мутантов вручную является практически
невозможным)
* Сильно возрастают затраты на проведение тестирования (вместо одного запуска каждого теста требуется выполнить N
запусков; кроме того, дополнительное время тратится на генерацию мутантов)Bonus: оценка тестового покрытия / нестабильность тестового покрытия
Проблема покрытия потока управления - чувствительность к изменениям в исходном коде. Чем сильнее влияют изменения в
программе на тестовое покрытие, тем более нестабильным (fragile) является тестовое покрытие. Чем более нестабильным
является тестовое покрытие, тем менее адекватно оно оценивает качество тестирования.Можно применить мутационное тестирование для оценки тестового покрытия: ограничить набор трансформаций и посмотреть на
изменение тестового покрытия для мутантов.Проблема мутационного тестирования - эквивалентные мутанты, которые "зашумляют" итоговую оценку качества тестирования;
из-за шума снижается адекватность оценки.Можно применить тестовое покрытие для оценки мутационного тестирования: для каждого мутанта записывается трасса его
выполнения, у эквивалентных мутантов будут похожие трассы выполнения.# 11. Тестовые оракулы
Вид тестового оракула очень сильно зависит от того, какую эталонную модель мы используем. Для определения видов тестовых
оракулов применяются оценки точности и полноты. Точность - способность оракула избегать ложных обнаружений. Ложные
обнаружения при тестировании — лишние затраты на их обнаружение и игнорирование. Если их будет слишком много, оракул
никто не будет использовать из-за зашумления результатов. Полнота - способность оракула находить все ошибки. Пропущенные
ошибки при тестировании — дополнительные затраты на их исправление позднее. Если оракул пропускает много ошибок, его
необходимо усиливать другими способами. Виды тестовых оракулов:* слабые
* средние
* сильные## Слабые оракулы
- падение (Segmentation fault, Core dump):
* работают всегда
* практически ничего не говорят о причине ошибки- сбой при работе в обычном окружении (NullPointerException, OutOfMemoryException, ClassNotFoundException):
* работают при поддержке стандартной среды выполнения
* содержат определенную информацию о месте ошибки- сбой при работе в специальном тестовом окружении (Valgrind):
* предоставляют специальную среду выполнения
* позволяют весьма точно определить причину ошибокValgrind - фреймворк для построения средств динамического анализа программ.
Слабые оракулы обеспечивают хорошую точность и плохую полноту.
## Средние оракулы
- Assertion, тесты
* Требуют определенных усилий со стороны разработчиков
* В зависимости от степени усилий, будут более или менее точно указывать на место возникновения ошибкиСредние оракулы обеспечивают хорошую точность и среднюю полноту.
## Сильные оракулы
- эталонная реализация (предыдущая версия программы, формально верифицированная реализация, автоматически
сгенерированная версия)
- "обратная функция" (прямое/обратное преобразование Фурье, архиватор/деархиватор, кодер/декодер видео)Сильные оракулы обеспечивают хорошую точность и хорошую полноту.
Слабые и средние оракулы можно генерировать автоматически.
Генерация слабых оракулов уже готова: слабый оракул предоставляется средой выполнения, если что-то упало, мы всегда об
этом узнаем. В явном виде используются весьма редко (при случайном тестировании). Сложно понять, где произошла ошибка.
Не всегда очевидно, в чем именно заключается ошибка.Генерация средних оракулов: средние оракулы разрабатываются параллельно с разработкой ПО, при возникновении проблемы мы
сразу узнаем о ней.# 12. Случайное тестирование. Фаззинг.
Генерация тестов - развитие идеи генерации тестовых оракулов, полная автоматизация процесса тестирования. Основная идея
- заставить компьютер работать вместо нас: дешевле, быстрее и без человеческого фактора. Генерация тестов включает в
себя автоматическую генерацию компонентов тестов: входные данные, последовательности вызовов API, тестовые оракулы.
Результаты генерации тестов очень сильно зависят от того, что именно мы тестируем.Фаззинг - прародитель случайного тестирования, когда мы генерируем полностью случайные данные. Вариант smoke testing.
Используем слабые оракулы, при необходимости вставляем заглушки. Случайные данные: набор байт, вызовы функций API,
пользовательский ввод. С течением времени результаты фаззинга не становились лучше: многие баги, обнаруженные фаззингом,
были исправлены, но появилось еще больше новых.# 13. Случайное тестирование. Генеративный и мутационный подходы.
```
Проблема валидности данных:
Полностью случайные данные являются невалидными входными данными для большинства программ. Большинство программ ожидают структурированные входные данные.
```Генеративный подход - если мы знаем структуру, то мы можем ей воспользоваться: генерируем отдельные элементы,
комбинируем их в соответствии с заданной структурой, вносим случайные нарушения структуры. Структура - набор правил
генерации, грамматика, формальная спецификация, стандарт на формат входных файлов.```
Проблема сложной структуры:
Иногда структура входных данных является слишком сложной.
```Мутационный подход - обычно у нас есть какой-то набор тестовых входных данных: подвергаем тестовые данные мутации, при
этом возможно использование знания структуры данных, часть данных может генерироваться случайно. Мутационные
трансформации - добавление нового фрагмента, удаление старого фрагмента, изменение фрагмента, обмен двух фрагментов
местами, замена значений на граничные.# 14. Случайное тестирование. Направленное случайное тестирование и друзья.
```
Проблема скелета в шкафу:
Добраться до самых дальних закоулков нельзя.
```Направленный подход решает основные проблемы случайного тестирования:
- некорректные тесты -> более строгие правила генерации/мутации, явный учет некорректных тестов
- эквивалентные тесты -> обнаружение тестов (статически, динамически), на которых программа ведет себя одинаковым
образом
- длинные тесты -> минимизация тестов (дихотомия, стохастический поиск, эволюционные алгоритмы)Каждый новый тест минимально отличается от имеющихся, каждый новый тест улучшает тестовое покрытие, каждый новый тест
должен генерироваться достаточно быстро.Concolic (concrete + symbolic) testing - комбинируем информацию о *конкретных*
выполнениях программы и информацию о *символическом* поведении программы. Комбинация статического и динамического
анализов. Проблема concolic testing — это сложно (очень (очень-очень)):- инструментирование программы
- моделирование памяти
- взрыв пространства состояний```
Проблема мистера Икс:
Некоторые части системы могут быть "черным ящиком".
```# 15. Регрессионное тестирование. Выборочное регрессионное тестирование.
ПО в процессе разработки изменяется инкрементально, небольшими независящими шагами (изменение существующего кода,
исправление ошибок, добавление новой функциональности, адаптация имеющихся компонентов к новым задачам). Любые (даже
самые незначительные) изменения могут серьезно повлиять на качество ПО. После любого изменения требуется проверить, что
в программе не появилось новых ошибок. Для этого мы выполняем имеющиеся тесты и проверяем, что они успешно завершаются.
Основной вид тестирования в процессе разработки ПО — это **регрессионное тестирование**.Первая проблема регрессионного тестирования - выбор набора тестов после изменения в программе: консервативный (выбираем
все имеющиеся тесты; полное регрессионное тестирование) и случайный (выбираем случайное подмножество всех тестов;
случайное выборочное регрессионное тестирование) подход.Выборочное регрессионное тестирование должно удовлетворять следующим свойствам:
- Полнота — способность выбирать те тесты, которые могут обнаружить ошибки, связанные с изменениями в коде
- Точность — способность пропускать такие тесты, которые не изменяют своего поведения на модифицированной программе
- Эффективность — способность выполняться быстрее, чем полное регрессионное тестирование
- Универсальность — применимость в большинстве практических ситуацийУмный подход - выбирать тесты, которые "затрагивают" при выполнении измененные части программы (выборочное регрессионное
тестирование). Все подходы к ВРТ различаются по двум основным критериям: способ идентификации измененных программных
компонентов и метод получения информации о покрытии элементов программы тестами.# 16. Регрессионное тестирование. Другие проблемы.
Вторая проблема регрессионного тестирования: управление регрессионными тестами (добавление новых, удаление старых
тестов). Добавление новых тестов происходит:* когда в ПО появилась новая функциональность
* когда в ПО была исправлена ошибка
* когда мы хотим улучшить тестовое покрытие ПО
* когда мы можем себе позволить добавить новый неповторяющийся тестС течением времени число тестов увеличивается; чем больше тестов, тем лучше тестовое покрытие; проблемы начинаются,
когда тестов становится слишком много.Удаление старых тестов происходит когда:
* никогда
* когда тест дублирует другие тесты
* когда тест не улучшает тестовое покрытие
* когда тест ни разу не обнаружил ошибки за все время тестирования
* когда тест обнаруживает такие же ошибки, как и другие тестыТретья проблема регрессионного тестирования: приоритизация регрессионных тестов. Можно изменять порядок, в котором
запускаются регрессионные тесты:* чем раньше мы узнаем о том, что в ПО появилась регрессионная ошибка, тем скорее мы сможем приступить к ее исправлению
* часто причиной непрохождения различных (напрямую не связанных друг с другом) тестов является одна и та же ошибка
* иногда время на тестирование является ограниченным, и необходимо найти наибольшее число ошибок с учетом всех
ограниченийСпособы приоритизации:
- при помощи интуиции (необходима хорошая интуиция; также можно использовать имеющийся опыт разработки)
- на основе знаний о тестовом покрытии ПО (сперва выполняются тесты, которые имеют наибольшее покрытие / покрывают более
важные компоненты ПО)
- на основе истории разработки (приоритет отдается тестам, которые чаще других обнаруживали регрессионные ошибки;
первыми выполняются тесты, проверяющие корректность работы наиболее "проблемных" компонентов ПО)
- случайным образом (подход перекликается со случайным ВРТ)
- на основе характеристик тестов (первыми выполняются тесты с наименьшим временем выполнения; приоритет отдается тестам,
которые наиболее активно работают с окружением программной системы)Четвертая проблема регрессионного тестирования: анализ результатов. Если все тесты проходят — все хорошо. Если тест не
проходит — то все зависит от того, по какой причине он не проходит.Bonus:
РТ на практике используется очень часто (TDD, Agile Development, RUP), ВРТ практически не используется. Причины:
* крайняя сложность выбора регрессионных тестов
* опасность пропустить регрессионную ошибку при использовании небезопасного ВРТ
* страх перед использованием "непонятной"" технологии
* простота экстенсивного пути решения проблем РТ
* ~~отсутствие хорошей инструментальной поддержки~~
* недетерминизм в тестах
* эффект "лавины" (пропущенный тест в ВРТ может дальше привести к каскадному пропуску множества тестов)# 17. Дебаггинг. Дельта-дебаггинг.
Debugging - процесс поиска ошибок в программе. Поиск ошибок:
- запустить тест
- тест выполнит фрагмент кода с ошибкой — это вызовет порчу состояния программы
- результат работы программы будет некорректнымЕсли решена проблема наблюдаемости, дебаггинг не нужен.
Основная проблема - наблюдение за состоянием программы. С это проблемой может помочь отладчик. Две основные задачи
отладчика:1. Пошаговое выполнение программы
2. Наблюдение за внутренним состоянием программы Основное свойство отладчика - тесная интеграция со средой выполнения (
понимание того, что такое инструкция; возможность останавливать выполнение в произвольные моменты времени; знание
модели памяти; способность модифицировать выполняемый код и т. д.).Time-traveling debugging - отладка с возможностью выполнения программы в обратную сторону: возможность детального
исследования поведения программы, нет необходимости перезапускать программу. Осуществляется за счет использования
обратных функций, трассировки, записи состояния памяти (memory snapshots). Осложнено за счет неявных входных данных (
дата/время, внешнее состояние (БД, сериализованные данные, и т. д.), работа с аппаратурой, взаимодействие с другими
программами). Чем больше неявных данных мы хотим учитывать, тем сложнее это сделать эффективно.Time-traveling virtual machine - все то же самое, но на уровне виртуальной машины; запись взаимодействия ПО с
аппаратурой; возможность отладки целого ансамбля программ; никаких проблем с неявными входными данными. TTVM позволяют
отладить ошибки даже в ОС.Delta-debugging - способ автоматической минимизации теста. Поиск минимального объема данных в программе, приводящего к
ошибке. Удаление любого компонента из минимального теста приводит к исчезновению ошибки. Чем меньше тест, тем проще его
анализировать. Подходы:* субоптимальный (дихотомия)
* квази-оптимальный (полный перебор)
* оптимальный (умный перебор)
* супер-оптимальный (умный перебор с учетом доменной области)Готовых "коробочных" средств для delta-debugging над данными нет.