После полной интеграции системы можно оценить такие интеграционные свойства системы, как производительность и надежность. Чтобы убедиться, что система может работать с заданной нагрузкой, разрабатываются тесты для измерения производительности. Обычно планируются серии тестов с постоянным увеличением нагрузки, пока производительность системы не начнет снижаться.
Некоторые классы систем проектируются с учетом работы под определенной нагрузкой. Например, система обработки транзакций проектируется так, чтобы обрабатывать 100 транзакций в секунду; сетевая операционная система – чтобы обрабатывать информацию от 200 отдельных терминалов. При тестировании с нагрузкой выполнение тестов начинается с максимальной нагрузки, указанной в проекте системы, и продолжается до тех пор, пока не произойдет сбой в работе системы. Данный тип тестирования выполняет две функции [4].
1. Тестируется поведение системы во время сбоя. В процессе эксплуатации могут возникать ситуации, при которых нагрузка в системе превышает максимально допустимую. В таких ситуациях очень важно, чтобы сбой в системе не приводил к нарушению целостности данных или к потере сервисных возможностей.
2. Чтобы выявить дефекты, которые не проявляются в обычных режимах работы, система подвергается тестированию с нагрузкой. Хотя подобные дефекты не приводят к ошибкам при обычном использовании системы, на практике могут возникнуть необычные комбинации стандартных условий; именно они воспроизводятся во время тестирования с нагрузкой [4].
Тестирование с нагрузкой чаще всего применяется в распределенных системах. В таких системах при большой нагрузке сеть порой "забивается" данными, которыми обмениваются разные процессы. Постепенно процессы все больше замедляются, поскольку они ожидают данные запросов от других процессов.
Было рассмотрено два основных подхода к тестированию программного обеспечения – компонентное тестирование, при котором компоненты системы тестируются независимо друг от друга, и тестирование сборки, когда компоненты интегрированы в подсистемы и тестируется конечная система. Эти подходы в равной мере применимы и к объектно-ориентированным системам. Однако системы, разработанные по функциональной модели, и объектно-ориентированные системы имеют существенные отличия.
1. Объекты, как отдельные программные компоненты, представляют собой нечто большее, чем отдельные подпрограммы или функции.
2. Объекты, интегрированные в подсистемы, обычно слабо связаны между собой и поэтому сложно определить "самый верхний уровень" системы.
3. При анализе повторно используемых объектов их исходный код может быть недоступным для испытателей [3-5].
Эти отличия означают, что при проверке объектов можно применять тестирование методом белого ящика, основанное на анализе кода, а при тестировании сборки следует использовать другие подходы. Применительно к объектно-ориентированным системам можно определить четыре уровня тестирования.
1. Тестирование отдельных методов (операций), ассоциированных с объектами. Обычно методы представляют собой функции или процедуры. Поэтому здесь можно использовать тестирование методами черного и белого ящиков, которые рассматривались ранее.
2. Тестирование отдельных классов объектов. Принцип тестирования методом черного ящика остается без изменений, однако, понятие "класса эквивалентности" необходимо расширить. Тестирование классов объектов обсуждается в разделе 2.1.
3. Тестирование кластеров объектов. Нисходящая и восходящая сборки оказываются не пригодными для создания групп связанных объектов. Поэтому здесь следует применять другие методы тестирования, например основанные на сценариях. Эти методы рассматриваются в разделе 2.2.
4. Тестирование системы. Верификация и аттестация объектно-ориентированной системы выполняется точно так же, как и для любых других типов систем [3,4,5].
В настоящее время методы тестирования объектно-ориентированных систем достаточно хорошо разработаны [5]. В следующих разделах приведен обзор основных методов тестирования объектно-ориентированных систем.
Подход к тестовому покрытию систем, описанный в разделе 1.3, требует, чтобы все операторы в программе выполнялись хотя бы один раз, а также, чтобы выполнялись все ветви программы. При тестировании объектов полное тестовое покрытие включает:
1. раздельное тестирование всех методов, ассоциированных с объектом;
2. проверку всех атрибутов, ассоциированных с объектом;
3. проверку всех возможных состояний объекта (для этого необходимо моделирование событий, приводящих к изменению состояния объекта).
Использование наследования усложняет разработку тестов для классов объектов. Если класс предоставляет методы, унаследованные от подклассов, то необходимо протестировать все подклассы со всеми унаследованными методами. Понятие классов эквивалентности можно применить также и к классам объектов. Здесь тестовые данные из одного класса эквивалентности тестируют одни и те же свойства объектов [5,6].
При разработке объектно-ориентированных систем различия между уровнями интеграции менее заметны, поскольку методы и данные компонуются (интегрируются) в виде объектов и классов объектов. Тестирование классов объектов соответствует тестированию отдельных элементов. В объектно-ориентированных системах нет непосредственного эквивалента тестированию модулей. Однако считается, что группы классов, которые совместно предоставляют набор сервисов, следует тестировать вместе [3,6]. Такой вид тестирования называется тестированием кластеров.
Для объектно-ориентированных систем не подходит ни восходящая, ни нисходящая интеграция системы, поскольку здесь нет строгой иерархии объектов. Поэтому создание кластеров основывается на выделении методов и сервисов, реализуемых посредством этих кластеров. При тестировании сборки объектно-ориентированных систем используется три подхода.
1. Тестирование сценариев и вариантов использования. Варианты использования или сценарии описывают какой-либо один режим работы системы. Тестирование может базироваться на описании этих сценариев и кластеров объектов, реализующих данный вариант использования.
2. Тестирование потоков. Этот подход основывается на проверке системных откликов на ввод данных или группу входных событий. Объектно-ориентированные системы, как правило, событийно-управляемые, поэтому для них особенно подходит данный вид тестирования. При использовании этого подхода необходимо знать, как в системе проходит обработка потоков событий.
3. Тестирование взаимодействий между объектами. Это метод тестирования групп взаимодействующих объектов [4,6]. Этот промежуточный уровень тестирования сборки системы основан на определении путей "метод-сообщение", отслеживающих последовательности взаимодействий между объектами.
Тестирование сценариев часто оказывается более эффективным, чем другие методы тестирования. Сам процесс тестирования можно спланировать так, чтобы в первую очередь проверялись наиболее вероятные сценарии и только затем исключительные сценарии. Поэтому тестирование сценариев удовлетворяет основному принципу, согласно которому при тестировании больше внимания необходимо уделять наиболее часто используемым частям системы.
После выбора сценариев для тестирования системы важно убедиться, что все методы каждого класса будут выполняться хотя бы один раз. Для этого можно составить технологическую карту проверок классов объектов и методов и при выборе сценария отмечать выполняемый метод. Конечно, все комбинации методов выполнить невозможно, но, по крайней мере, можно удостовериться, что все методы протестированы как часть какой-либо последовательности выполняемых методов [6].
Тестирование – дорогой и трудоемкий этап разработки программных систем. Поэтому создан широкий спектр инструментальных средств для поддержки процесса тестирования, которые значительно сокращают расходы на него.
На рисунке 9 показаны возможные инструментальные средства тестирования и отношения между ними.
1. Организатор тестов. Управляет выполнением тестов. Он отслеживает тестовые данные, ожидаемые результаты и тестируемые функции программы.
2. Генератор тестовых данных. Генерирует тестовые данные для тестируемой программы. Он может выбирать тестовые данные из базы данных или использовать специальные шаблоны для генерации случайных данных необходимого вида.
3. Оракул. Генерирует ожидаемые результаты тестов. В качестве оракулов могут выступать предыдущие версии программы или исследуемого объекта. При тестировании параллельно запускаются оракул и тестируемая программа и сравниваются результаты их выполнения.
4. Компаратор файлов. Сравнивает результаты тестирования с результатами предыдущего тестирования и составляет отчет об обнаруженных различиях. Компараторы особенно важны при сравнении различных версий программы. Различия в результатах указывают на возможные проблемы, существующие в новой версии системы.