Основы тестирования программного обеспечения

Интеграционное тестирование

Разбить на страницы
Показывать лекцию целиком

Основное назначение тестирования взаимодействий состоит в том, чтобы убедиться, что происходит правильный обмен сообщениями между объектами, классы которых уже прошли тестирование в автономном режиме (на модульном уровне тестирования).

Тестирование взаимодействия или интеграционное тестирование представляет собой тестирование собранных вместе, взаимодействующих модулей (объектов). В интеграционном тестировании можно объединять разное количество объектов - от двух до всех объектов тестируемой системы. Интеграционное тестирование отличается от системного тем, что:

  • при интеграционном тестировании используется подход "белого ящика", а при системном - "черного ящика";
  • целью интеграционного тестирования является только проверка правильности взаимодействия объектов, тогда как целью системного - проверка правильности функционирования системы в целом.
  • Идентификация взаимодействий

    Взаимодействие объектов представляет собой просто запрос одного объекта ( отправителя ) на выполнение другим объектом ( получателем ) одной из операций получателя и всех видов обработки, необходимых для завершения этого запроса.

    В ситуациях, когда в качестве основы тестирования взаимодействий объектов выбраны только спецификации общедоступных операций, тестирование намного проще, чем когда такой основой служит реализация. Мы ограничимся тестированием общедоступного интерфейса. Такой подход вполне оправдан, поскольку мы полагаем, что классы уже успешно прошли модульное тестирование. Тем не менее, выбор такого подхода отнюдь не означает, что не нужно возвращаться к спецификациям классов, дабы убедиться в том, что тот или иной метод выполнил все необходимые вычисления. Это обусловливает необходимость проверки значений атрибутов внутреннего состояния получателя, в том числе любых агрегированных атрибутов, т.е. атрибутов, которые сами являются объектами. Основное внимание уделяется отбору тестов на основе спецификации каждой операции из общедоступного интерфейса класса.

    Взаимодействия неявно предполагаются в спецификации класса, в которой установлены ссылки на другие объекты. В разделе 4 рассматривалось тестирование примитивных классов. Такие объекты представляют собой простейшие компоненты системы и, несомненно, играют важную роль при выполнении любой программы. Тем не менее, в объектно-ориентированной программе существует сравнительно небольшое количество примитивных классов, которые реалистично моделируют объекты задачи и все отношения между этими объектами. Обычным явлением для хорошо спроектированных объектно- ориентированных программ является использование непримитивных классов; в этих программах им отводится главенствующая роль.

    Выявить такие взаимодействующие классы можно, используя отношения ассоциации (в том числе отношения агрегирования и композиции), представленные на диаграмме классов. Ассоциации такого рода преобразуются в интерфейсы класса, а тот или иной класс взаимодействует с другими классами посредством одного или нескольких способов:

    Тип 1. Общедоступная операция имеет один или большее число формальных параметров объектного типа. Сообщение устанавливает ассоциацию между получателем и параметром, которая позволяет получателю взаимодействовать с этим параметрическим объектом.

    Тип 2. Общедоступная операция возвращает значения объектного типа. На класс может быть возложена задача создания возвращаемого объекта, либо он может возвращать модифицированный параметр.

    Тип 3. Метод одного класса создает экземпляр другого класса как часть своей реализации.

    Тип 4. Метод одного класса ссылается на глобальный экземпляр некоторого другого класса. Разумеется, принципы хорошего тона в проектировании рекомендуют минимальное использование глобальных объектов. Если реализация какого-либо класса ссылается на некоторый глобальный объект, рассматривайте его как неявный параметр в методах, которые на него ссылаются.

    Приведем еще раз таблицу разделения классов на примитивные и непримитивные типы (табл. 3.1):

    Типы классов
    КлассТип
    TBearingParam Примитивный
    TAxleParam Примитивный
    TCommand Примитивный
    TLog Примитивный
    TCommandQueue Непримитивный
    Класс Непримитивный
    TStore Непримитивный
    TTerminalBearing Непримитивный
    TTerminalAxle Непримитивный
    TModel Непримитивный
    MainForm Непримитивный
    Типы взаимодействия классов
    Непримитивные типыTbearing ParamTaxle ParamTcommandTCommand Queue TStoreTTerminal BearingTTerminal AxleTLogTmodel
    TCommandQueue 1 1 3 1 1
    TStore 3 1 1
    TTerminalBearing 3
    TTerminalAxle 3
    TModel 3 3 3 3 3
    MainForm 3

    Таким образом, интеграционному тестированию будут подвергнуты взаимодействия перечисленных непримитивных классов.

    Выбор тестовых случаев

    Исчерпывающее тестирование, другими словами, прогон каждого возможного тестового случая, покрывающего каждое сочетание значений - это, вне всяких сомнений, надежный подход к тестированию. Однако во многих ситуациях количество тестовых случаев достигает таких больших значений, что обычными методами с ними справиться попросту невозможно. Если имеется принципиальная возможность построения такого большого количества тестовых случаев, на построение и выполнение которых не хватит никакого времени, должен быть разработан систематический метод определения, какими из тестовых случаев следует воспользоваться. Если есть выбор, то мы отдаем предпочтение таким тестовым случаям, которые позволяют найти ошибки, в обнаружении которых мы заинтересованы больше всего.

    Существуют различные способы определения, какое подмножество из множества всех возможных тестовых случаев следует выбирать. При любом подходе мы заинтересованы в том, чтобы систематически повышать уровень покрытия.

    Подробное описание тестового случая

    Продемонстрируем тестирование взаимодействий на примере класса TCommandQueue. Из табл. 3.2, которая была составлена на основе спецификаций классов, описанных в приложении 2, видно, что класс очереди команд взаимодействует со следующими классами:

    TBearingParam,
    TAxleParam,
    TCommand,
    TStore,
    TterminalBearing.

    С объектом TCommand осуществляется взаимодействие третьего типа, т. е. TCommandQueue создает объекты класса TCommand как часть своей внутренней реализации. С остальными классами осуществляется взаимодействие первого типа: ссылки на объекты классов TStore и TTerminalBearing передаются как параметры в конструктор TCommandQueue, а ссылки на объекты классов TBearingParam и TAxleParam передаются в метод TCommandQueue.AddCommand.

    Одновременно с изучением этого раздела можно открыть проект IntegrationTesting\IntegrationTests.sln.

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

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

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

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

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

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

  • Метод Init, в котором создаются объекты классов TStore, TterminalBearing и объект типа TcommandQueue. Этот метод необходимо вызывать в начале каждого теста, чтобы тестируемые объекты создавались вновь:
    private void Init()
    {
    TB = new TTerminalBearing();
    S = new TStore();
    CommandQueue=new TCommandQueue(S,TB);
    S.CommandQueue=CommandQueue;
    }
  • Методы, реализующие тесты. Каждый тест реализован в отдельном методе.
  • Метод Run, в котором вызываются методы тестов.
  • Метод dump, который сохраняет в log-файле теста информацию обо всех командах, находящихся в очереди в формате - номер позиции в очереди: полное название команды.
  • Точку входа в программу - метод Main, в котором происходит создание экземпляра класса TCommandQueueTester и запуск метода Run.
  • Сначала создадим тест, который проверяет, создается ли объект типа TСommand, и добавляется ли команда в конец очереди.

    private void TCommandQueueTest1()
    {
    Init();
    LogMessage("///////// TCommandQueue Test1 /////////////");
    LogMessage("Проверяем, создается ли объект типа TCommand");
    // В очереди нет команд
    dump();
    // Добавляем команду
    // параметр = -1 означает, что команда должна быть добавлена
    //в конец очереди
    CommandQueue.AddCommand(TCommand.GetR,0,0,0,new
    TBearingParam(),new TAxleParam(),-1);
    LogMessage("Command added");
    // В очереди одна команда
    dump();
    }

    В этот класс включены еще два разработанных теста.

    Описание тестовых процедур

    Как запустить тест?

    Для выполнения этого теста в методе Run необходимо вызвать метод TCommandQuеueTest1() и запустить программу на выполнение:

    private void Run()
    {
      TCommandQueueTest1();
    }

    Проверка результатов выполнения тестов (сравнение с ожидаемым результатом)

    После завершения теста следует просмотреть текстовый журнал теста ( ..\IntegrationTesting\bin\Debug\test.log ), чтобы сравнить полученные результаты с ожидаемыми результатами, заданными в спецификации тестового случая TCommandQueueTest1.

    //////////////////// TCommandQueue Test1 //////////////////
    Проверяем, создается ли объект типа TCommand
    0 commands in command queue
    Command added
    1 commands in command queue
    0 : ПОЛУЧИТЬ ИЗ ВХОДНОЙ ЯЧЕЙКИ

    Задание 2

    Для тестирования взаимодействия остальных непримитивных классов (табл. 2.1) по аналогии с приведенным примером требуется самостоятельно разработать спецификации тестовых случаев, соответствующие тесты, провести тестирование и составить тестовые отчеты (табл. 2.2).

    Страницы:

    Основное назначение тестирования взаимодействий состоит в том, чтобы убедиться, что происходит правильный обмен сообщениями между объектами, классы которых уже прошли тестирование в автономном режиме (на модульном уровне тестирования).

    Тестирование взаимодействия или интеграционное тестирование представляет собой тестирование собранных вместе, взаимодействующих модулей (объектов). В интеграционном тестировании можно объединять разное количество объектов - от двух до всех объектов тестируемой системы. Интеграционное тестирование отличается от системного тем, что:

  • при интеграционном тестировании используется подход "белого ящика", а при системном - "черного ящика";
  • целью интеграционного тестирования является только проверка правильности взаимодействия объектов, тогда как целью системного - проверка правильности функционирования системы в целом.
  • Идентификация взаимодействий

    Взаимодействие объектов представляет собой просто запрос одного объекта ( отправителя ) на выполнение другим объектом ( получателем ) одной из операций получателя и всех видов обработки, необходимых для завершения этого запроса.

    В ситуациях, когда в качестве основы тестирования взаимодействий объектов выбраны только спецификации общедоступных операций, тестирование намного проще, чем когда такой основой служит реализация. Мы ограничимся тестированием общедоступного интерфейса. Такой подход вполне оправдан, поскольку мы полагаем, что классы уже успешно прошли модульное тестирование. Тем не менее, выбор такого подхода отнюдь не означает, что не нужно возвращаться к спецификациям классов, дабы убедиться в том, что тот или иной метод выполнил все необходимые вычисления. Это обусловливает необходимость проверки значений атрибутов внутреннего состояния получателя, в том числе любых агрегированных атрибутов, т.е. атрибутов, которые сами являются объектами. Основное внимание уделяется отбору тестов на основе спецификации каждой операции из общедоступного интерфейса класса.

    Взаимодействия неявно предполагаются в спецификации класса, в которой установлены ссылки на другие объекты. В разделе 4 рассматривалось тестирование примитивных классов. Такие объекты представляют собой простейшие компоненты системы и, несомненно, играют важную роль при выполнении любой программы. Тем не менее, в объектно-ориентированной программе существует сравнительно небольшое количество примитивных классов, которые реалистично моделируют объекты задачи и все отношения между этими объектами. Обычным явлением для хорошо спроектированных объектно- ориентированных программ является использование непримитивных классов; в этих программах им отводится главенствующая роль.

    Выявить такие взаимодействующие классы можно, используя отношения ассоциации (в том числе отношения агрегирования и композиции), представленные на диаграмме классов. Ассоциации такого рода преобразуются в интерфейсы класса, а тот или иной класс взаимодействует с другими классами посредством одного или нескольких способов:

    Тип 1. Общедоступная операция имеет один или большее число формальных параметров объектного типа. Сообщение устанавливает ассоциацию между получателем и параметром, которая позволяет получателю взаимодействовать с этим параметрическим объектом.

    Тип 2. Общедоступная операция возвращает значения объектного типа. На класс может быть возложена задача создания возвращаемого объекта, либо он может возвращать модифицированный параметр.

    Тип 3. Метод одного класса создает экземпляр другого класса как часть своей реализации.

    Тип 4. Метод одного класса ссылается на глобальный экземпляр некоторого другого класса. Разумеется, принципы хорошего тона в проектировании рекомендуют минимальное использование глобальных объектов. Если реализация какого-либо класса ссылается на некоторый глобальный объект, рассматривайте его как неявный параметр в методах, которые на него ссылаются.

    Приведем еще раз таблицу разделения классов на примитивные и непримитивные типы (табл. 3.1):

    Типы классов
    КлассТип
    TBearingParam Примитивный
    TAxleParam Примитивный
    TCommand Примитивный
    TLog Примитивный
    TCommandQueue Непримитивный
    Класс Непримитивный
    TStore Непримитивный
    TTerminalBearing Непримитивный
    TTerminalAxle Непримитивный
    TModel Непримитивный
    MainForm Непримитивный
    Типы взаимодействия классов
    Непримитивные типыTbearing ParamTaxle ParamTcommandTCommand Queue TStoreTTerminal BearingTTerminal AxleTLogTmodel
    TCommandQueue 1 1 3 1 1
    TStore 3 1 1
    TTerminalBearing 3
    TTerminalAxle 3
    TModel 3 3 3 3 3
    MainForm 3

    Таким образом, интеграционному тестированию будут подвергнуты взаимодействия перечисленных непримитивных классов.

    Выбор тестовых случаев

    Исчерпывающее тестирование, другими словами, прогон каждого возможного тестового случая, покрывающего каждое сочетание значений - это, вне всяких сомнений, надежный подход к тестированию. Однако во многих ситуациях количество тестовых случаев достигает таких больших значений, что обычными методами с ними справиться попросту невозможно. Если имеется принципиальная возможность построения такого большого количества тестовых случаев, на построение и выполнение которых не хватит никакого времени, должен быть разработан систематический метод определения, какими из тестовых случаев следует воспользоваться. Если есть выбор, то мы отдаем предпочтение таким тестовым случаям, которые позволяют найти ошибки, в обнаружении которых мы заинтересованы больше всего.

    Существуют различные способы определения, какое подмножество из множества всех возможных тестовых случаев следует выбирать. При любом подходе мы заинтересованы в том, чтобы систематически повышать уровень покрытия.

    Подробное описание тестового случая

    Продемонстрируем тестирование взаимодействий на примере класса TCommandQueue. Из табл. 3.2, которая была составлена на основе спецификаций классов, описанных в приложении 2, видно, что класс очереди команд взаимодействует со следующими классами:

    TBearingParam,
    TAxleParam,
    TCommand,
    TStore,
    TterminalBearing.

    С объектом TCommand осуществляется взаимодействие третьего типа, т. е. TCommandQueue создает объекты класса TCommand как часть своей внутренней реализации. С остальными классами осуществляется взаимодействие первого типа: ссылки на объекты классов TStore и TTerminalBearing передаются как параметры в конструктор TCommandQueue, а ссылки на объекты классов TBearingParam и TAxleParam передаются в метод TCommandQueue.AddCommand.

    Одновременно с изучением этого раздела можно открыть проект IntegrationTesting\IntegrationTests.sln.

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

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

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

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

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

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

  • Метод Init, в котором создаются объекты классов TStore, TterminalBearing и объект типа TcommandQueue. Этот метод необходимо вызывать в начале каждого теста, чтобы тестируемые объекты создавались вновь:
    private void Init()
    {
    TB = new TTerminalBearing();
    S = new TStore();
    CommandQueue=new TCommandQueue(S,TB);
    S.CommandQueue=CommandQueue;
    }
  • Методы, реализующие тесты. Каждый тест реализован в отдельном методе.
  • Метод Run, в котором вызываются методы тестов.
  • Метод dump, который сохраняет в log-файле теста информацию обо всех командах, находящихся в очереди в формате - номер позиции в очереди: полное название команды.
  • Точку входа в программу - метод Main, в котором происходит создание экземпляра класса TCommandQueueTester и запуск метода Run.
  • Сначала создадим тест, который проверяет, создается ли объект типа TСommand, и добавляется ли команда в конец очереди.

    private void TCommandQueueTest1()
    {
    Init();
    LogMessage("///////// TCommandQueue Test1 /////////////");
    LogMessage("Проверяем, создается ли объект типа TCommand");
    // В очереди нет команд
    dump();
    // Добавляем команду
    // параметр = -1 означает, что команда должна быть добавлена
    //в конец очереди
    CommandQueue.AddCommand(TCommand.GetR,0,0,0,new
    TBearingParam(),new TAxleParam(),-1);
    LogMessage("Command added");
    // В очереди одна команда
    dump();
    }

    В этот класс включены еще два разработанных теста.

    Описание тестовых процедур

    Как запустить тест?

    Для выполнения этого теста в методе Run необходимо вызвать метод TCommandQuеueTest1() и запустить программу на выполнение:

    private void Run()
    {
      TCommandQueueTest1();
    }

    Проверка результатов выполнения тестов (сравнение с ожидаемым результатом)

    После завершения теста следует просмотреть текстовый журнал теста ( ..\IntegrationTesting\bin\Debug\test.log ), чтобы сравнить полученные результаты с ожидаемыми результатами, заданными в спецификации тестового случая TCommandQueueTest1.

    //////////////////// TCommandQueue Test1 //////////////////
    Проверяем, создается ли объект типа TCommand
    0 commands in command queue
    Command added
    1 commands in command queue
    0 : ПОЛУЧИТЬ ИЗ ВХОДНОЙ ЯЧЕЙКИ

    Задание 2

    Для тестирования взаимодействия остальных непримитивных классов (табл. 2.1) по аналогии с приведенным примером требуется самостоятельно разработать спецификации тестовых случаев, соответствующие тесты, провести тестирование и составить тестовые отчеты (табл. 2.2).

    Вернуться к учебному плану