учебники, программирование, основы, введение в,

 

Интеграционное тестирование и его особенности для объектно-ориентированного программирования

Особенности интеграционного тестирования для объектно-ориентированного программирования
Программный проект, написанный в соответствии с объектно-ориентированным подходом, будет иметь ГМП, существенно отличающийся от ГМП традиционной "процедурной" программы. Сама разработка проекта строится по другому принципу - от определения классов, используемых в программе, построения дерева классов к реализации кода проекта. При правильном использовании классов, точно отражающих прикладную область приложения, этот метод дает более короткие, понятные и легко контролируемые программы.
Объектно-ориентированное программное обеспечение является событийно управляемым. Передача управления внутри программы осуществляется не только путем явного указания последовательности обращений одних функций программы к другим, но и путем генерации сообщений различным объектам, разбора сообщений соответствующим обработчиком и передача их объектам, для которых данные сообщения предназначены. Рассмотренная ГМП в данном случае становится неприменимой. Эта модель, как минимум, требует адаптации к требованиям, вводимым объектно-ориентированным подходом к написанию программного обеспечения. При этом происходит переход от модели, описывающей структуру программы, к модели, описывающей поведение программы, что для тестирования можно классифицировать как положительное свойство данного перехода. Отрицательным аспектом совершаемого перехода для применения рассмотренных ранее моделей является потеря заданных в явном виде связей между модулями программы.
Перед тем как приступить к описанию графовой модели объектно-ориентированной программы, остановимся отдельно на одном существенном аспекте разработки программного обеспечения на языке объектно-ориентированного программирования (ООП), например, C++ или С#. Разработка программного обеспечения высокого качества для MS Windows или любой другой операционной системы, использующей стандарт "look and feel", с применением только вновь созданных классов практически невозможна. Программист должен будет затратить массу времени на решение стандартных задач по созданию пользовательского интерфейса. Чтобы избежать работы над давно решенными вопросами, во всех современных компиляторах предусмотрены специальные библиотеки классов. Такие библиотеки включают в себя практически весь программный интерфейс операционной системы и позволяют задействовать при программировании средства более высокого уровня, чем просто вызовы функций. Базовые конструкции и классы могут быть переиспользованы при разработке нового программного проекта. За счет этого значительно сокращается время разработки приложений. В качестве примера подобной системы можно привести библиотеку Microsoft Foundation Class для компилятора MS Visual C++ ".
Работа по тестированию приложения не должна включать в себя проверку работоспособности элементов библиотек, ставших фактически промышленным стандартом для разработки программного обеспечения, а только проверку кода, написанного непосредственно разработчиком программного проекта. Тестирование объектно-ориентированной программы должно включать те же уровни, что и тестирование процедурной программы - модульное, интеграционное и системное. Внутри класса отдельно взятые методы имеют императивный характер исполнения. Все языки ООП возвращают контроль вызывающему объекту, когда сообщение обработано. Поэтому каждый метод (функция - член класса) должен пройти традиционное модульное тестирование по выбранному критерию C (как правило, С1). В соответствии с введенными выше обозначениями, назовем метод Modi, а сложность тестирования - V(Modi,C). Все результаты, полученные в лекции 5 для тестирования модулей, безусловно, подходят для тестирования методов классов. Каждый класс должен быть рассмотрен и как субъект интеграционного тестирования. Интеграция для всех методов класса проводится с использованием инкрементальной стратегии снизу вверх. При этом мы можем переиспользовать тесты для классов-родителей тестируемого класса , что следует из принципа наследования - от базовых классов, не имеющих родителей, к самым верхним уровням классов.
Графовая модель класса, как и объектно-ориентированной программы, на интеграционном уровне в качестве узлов использует методы. Дуги данной ГМП (вызовы методов) могут быть образованы двумя способами:

  • Прямым вызовом одного метода из кода другого, в случае, если вызываемый метод виден (не закрыт для доступа средствами языка программирования) из класса, содержащего вызывающий метод, присвоим такой конструкции название Р-путь (P-path, Procedure path, процедурный путь).
  • Обработкой сообщения, когда явного вызова метода нет, но в результате работы "вызывающего" метода порождается сообщение, которое должно быть обработано "вызываемым" методом.

Для второго случая "вызываемый" метод может породить другое сообщение, что приводит к возникновению цепочки исполнения последовательности методов, связанных сообщениями. Подобная цепочка носит название ММ-путь (MM-path, Metod/Message path, путь метод/сообщение). ММ-путь заканчивается, когда достигается метод, который при отработке не вырабатывает новых сообщений (т. е. вырабатывает "сообщение покоя").
Пример ММ-путей приведен в. Данная конструкция отражает событийно управляемую природу объектно-ориентированного программирования и может быть взята в качестве основы для построения графовой модели класса или объектно-ориентированной программы в целом. В можно выделить четыре ММ-пути (1-4) и один P-путь (5):

  1. msg a http://localhost:3232/img/symbols/srarr.gifметод 3http://localhost:3232/img/symbols/srarr.gif msg 3http://localhost:3232/img/symbols/srarr.gif метод 4http://localhost:3232/img/symbols/srarr.gif msg d
  2. msg bhttp://localhost:3232/img/symbols/srarr.gif метод 1http://localhost:3232/img/symbols/srarr.gif msg 1http://localhost:3232/img/symbols/srarr.gif метод 4http://localhost:3232/img/symbols/srarr.gif msg d
  3. msg bhttp://localhost:3232/img/symbols/srarr.gif метод 1http://localhost:3232/img/symbols/srarr.gif msg 2http://localhost:3232/img/symbols/srarr.gif метод 5
  4. msg chttp://localhost:3232/img/symbols/srarr.gif метод 2
  5. callhttp://localhost:3232/img/symbols/srarr.gif метод 5

Здесь класс изображен как объединенное множество методов.
Введем следующие обозначения:
Kmsg- число методов класса, обрабатывающих различные сообщения;
Kem- число методов класса, которые не закрыты от прямого вызова из других классов программы.
Если рассматривать класс как программу P, то можно выделить следующие отличия от программы, построенной по процедурному принципу:

  • Значение Kext (число точек входа, которые могут быть вызваны извне) определяется как сумма методов - обработчиков сообщений Kmsg (например, в MS Visual C++ обозначаются зарезервированным словом afx_msg и используются для работы с картой сообщений класса) и тех методов, которые могут быть вызваны из других классов программы Kem. Это определяется самим разработчиком путем разграничения доступа к методам класса (с помощью ключевых слов разграничения доступа public, private, protect) при написании методов, а также назначении дружественных (friend) функций и дружественных классов. Таким образом, Kext = Kmsg + Kem, и имеет новый по сравнению с процедурным программированием физический смысл.
  • Принцип соединения узлов в ГМП, отражающий два возможных типа вызовов методов класса (через ММ-пути и Р-пути), что приводит к новому наполнению для множества М требуемых элементов.
  • Методы (модули) непрозрачны для внешних объектов, что влечет за собой неприменимость механизма упрощения графа модуля, используемого для получения графа вызовов в процедурном программировании.

С учетом приведенных замечаний, информационные связи между модулями программного проекта получают новый физический смысл, а формула оценки сложности интеграционного тестирования класса Cls принимает вид: V(Cls, C) = f (Kmsg, Kem)
В ходе интеграционного тестирования должны быть проверены все возможные внешние вызовы методов класса, как непосредственные обращения, так и вызовы, инициированные получением сообщений
Значение числа ММ-путей зависит от схемы обработки сообщений данным классом, что должно быть определено в спецификации класса. Например, для класса, изображенного в, сложность интеграционного тестирования V(Cls,C)=5 (множество неизбыточных тестов Т для класса составляют 4 ММ-пути плюс внешний вызов метода 5, т. е. Р-путь).
Данные - члены класса (данные, описанные в самом классе, и унаследованные от классов-родителей видимые извне данные) рассматриваются как "глобальные переменные", они должны быть протестированы отдельно на основе принципов тестирования потоков данных.
Когда класс программы P протестирован, объект данного класса может быть включен в общий граф G программного проекта, содержащий все ММ-пути и все вызовы методов классов и процедур, возможные в программе:
Программа P, содержащая n классов, имеет сложность интеграционного тестирования классов
V(P, C) =∑V(Clsi, C)
Формальным представлением описанного выше подхода к тестированию программного проекта служит классовая модель программного проекта, состоящая из дерева классов проектаи модели каждого класса, входящего в программный проект.
Таким образом и определяется классовая модель проекта для тестирования объектно-ориентированной программы. Как будет показано в дальнейшем, она поддерживает итерационный инкрементальный процесс разработки программного обеспечения.
Методика проведения тестирования программы, представленной в виде классовой модели программного проекта, включает в себя несколько этапов, соответствующих уровням тестирования:

  1. На первом уровне проводится тестирование методов каждого класса программы, что соответствует этапу модульного тестирования.
  2. На втором уровне тестируются методы класса, которые образуют контекст интеграционного тестирования каждого класса.
  3. На третьем уровне протестированный класс включается в общий контекст (дерево классов) программного проекта. Здесь становится возможным отслеживать реакцию программы на внешние события

Второй и третий уровни рассматриваемой модели соответствуют этапу интеграционного тестирования.
Для третьего уровня важным оказывается понятие атомарной системной функции (АСФ). АСФ - это множество, состоящее из внешнего события на входе системы, реакции системы на это событие в виде одного или более ММ-путей и внешнего события на выходе системы. В общем случае внешнее выходное событие может быть нулевым, т. е. неаккуратно написанное программное обеспечение может не обеспечивать внешней реакции на действия пользователя. АСФ, состоящая из входного внешнего события, одного ММ-пути и выходного внешнего события, может быть взята в качестве модели для нити (thread). Тестирование подобной АСФ в рамках классовой модели ГМП реализуется довольно сложно, так как хотя динамическое взаимодействие нитей (потоков) в процессе исполнения естественно фиксируется в log-файлах, запоминающих результаты трассировки исполнения программ, оно же достаточно сложно отображается на классовой ГМП. Причина в том, что классовая модель ориентирована на отображение статических характеристик проекта, а в данном случае требуется отображение поведенческих характеристик. Как правило, тестирование взаимодействия нитей в ходе исполнения программного комплекса выносится на уровень системного тестирования и использует другие более приспособленные для описания поведения модели. Например, описание поведения программного комплекса средствами языков спецификаций MSC, SDL, UML.
Явный учет границ между интеграционным и системным уровнями тестирования дает преимущество при планировании работ на фазе тестирования, а возможность сочетать различные методы и критерии тестирования в ходе работы над программным проектом дает наилучшие результаты.
Объектно-ориентированный подход, ставший в настоящее время неявным стандартом разработки программных комплексов, позволяет широко использовать иерархическую модель программного проекта, приведенная насхема иллюстрирует способ применения. Каждый класс рассматривается как объект модульного и интеграционного тестирования. Сначала каждый метод класса тестируется как модуль по выбранному критерию C. Затем класс становится объектом интеграционного тестирования. Далее осуществляется интеграция всех методов всех классов в единую структуру - классовую модель проекта, где в общую ГМП протестированные модули входят в виде узлов (интерфейсов вызова) без учета их внутренней структуры, а их детальные описания образуют контекст всего программного проекта.
Сама технология объектно-ориентированного программирования (одним из определяющих принципов которой является инкапсуляция с возможностью ограничения доступа к данным и методам - членам класса) позволяет применить подобную трактовку вхождения модулей в общую ГМП. При этом тесты для отдельно рассмотренных классов переиспользуются, входя в общий набор тестов для программы P.

http://localhost:3232/img/empty.gifПример интеграционного тестирования

Продемонстрируем тестирование взаимодействий на примере взаимодействия класса TCommandQueue и класса TСommand, а также, как и при модульном теcтировании, разработаем спецификацию тестового случая:


Таблица 4.2. Спецификация тестового случая для интеграционного тестирования

Названия взаимодействующих классов:TСommandQueue, TCommand

Название теста:TCommandQueueTest1

Описание теста:тест проверяет возможность создания объекта типа TCommand и добавления его в очередь при вызове метода AddCommand

Начальные условия:очередь команд пуста

Ожидаемый результат:в очередь будет добавлена одна команда

На основе этой спецификации разработан тестовый драйвер - класс TCommandQueueTester, который наследуется от класса Tester.
Класс содержит:

  • конструктор, в котором создаются объекты классов TStore, TterminalBearing и объект типа TcommandQueue
  • Методы, реализующие тесты. Каждый тест реализован в отдельном методе.
  • Метод Run, в котором вызываются методы тестов.
  • Метод dump, который сохраняет в Log-файле теста информацию обо всех командах, находящихся в очереди в формате - Номер позиции в очереди: полное название команды
  • Точку входа в программу - метод Main, в котором происходит создание экземпляра класса TСommandQueueTester.

public TCommandQueueTester()
{
TB = new TTerminalBearing();
S = new TStore();
CommandQueue=new TCommandQueue(S,TB);
S.CommandQueue=CommandQueue;
...
}
Пример 6.1. Объект типа TcommandQueue
TCommandQueueTester::TCommandQueueTester()
{
TB = new TTerminalBearing();
S = new TStore();
CommandQueue=new TCommandQueue(S,TB);
S->CommandQueue=CommandQueue;
}
Пример 6.1.1. Объект типа TcommandQueue (C++)
Теперь создадим тест, который проверяет, создается ли объект типа TСommand, и добавляется ли команда в конец очереди.
private void TCommandQueueTest1()
{
LogMessage("/////  TCommandQueue Test1  /////");
LogMessage("Проверяем, создается ли
объект типа TCommand");
// В очереди нет команд
dump();
// Добавляем команду
// параметр = -1 означает, что команда
// должна быть добавлена в конец очереди
CommandQueue.AddCommand(TCommand.GetR,0,0,0,
new TBearingParam(),new TAxleParam(),-1);
LogMessage("Command added");
// В очереди одна команда
dump();
}
Пример 6.2. Тест
void TCommandQueueTester::TCommandQueueTest1()
{
LogMessage("/////  TCommandQueue Test1  /////");
LogMessage("Проверяем, создается ли
объект типа TCommand");
// В очереди нет команд
dump();
// Добавляем команду
// параметр = -1 означает, что команда
// должна быть добавлена в конец очереди
CommandQueue.AddCommand(GetR,0,0,0,
new TBearingParam(),
new TAxleParam(),-1);
LogMessage("Command added");
// В очереди одна команда
dump();
}
Пример 6.2.1. Тест (C++)
В класс включены еще два разработанных теста.
После завершения теста следует просмотреть текстовый журнал теста, чтобы сравнить полученные результаты с ожидаемыми результатами, заданными в спецификации тестового случая TCommandQueueTest1.
/////    TCommandQueue Test1  /////
Проверяем, создается ли объект типа TCommand
0 commands in command queue
Command added
1 commands in command queue
0:  ПОЛУЧИТЬ ИЗ ВХОДНОЙ ЯЧЕЙКИ
Пример 6.3. Спецификация результатов теста

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика