Применение имитационного моделирования для тестирования web-интерфейса информационных систем управления

УДК 004.94

А. С. Язовский Омская гуманитарная академия

ПРИМЕНЕНИЕ ИМИТАЦИОННОГО МОДЕЛИРОВАНИЯ ДЛЯ ТЕСТИРОВАНИЯ WEB-ИНТЕРФЕЙСА информационных систем

УПРАВЛЕНИЯ

Статья посвящена проблемам тестирования клиентского web-интерфейса информационных систем управления с помощью имитационного моделирования.

Существующие библиотеки имитационного моделирования имеют ограничения в области использования. Рассматриваются особенности применения имитационного моделирования при работе с Java фреймворком Google Web Toolkit. Разработан механизм, использующий пре-генерацию кода для реализации mock-объектов для заданного интерфейса. Отмечены преимущества и недостатки предложенного метода.

Ключевые слова: тестирование, имитационное моделирование, mock-объект, reflection, интерпретатор, генератор, отложенное связывание.

Тестирование информационных систем - процесс исследования с целью получения информации о качестве продукта. К имитационному моделированию прибегают:

• когда дорого или невозможно экспериментировать на реальном объекте;

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

необходимо сымитировать поведение системы во времени.

Одной из реализаций имитационного моделирования в программировании являются mock-объекты.

Mock-объекты - тестировочный паттерн, суть которого состоит в замене объектов, используемых тестируемым кодом, на отладочные эквиваленты [1]. Например, для тестирования кода, обрабатывающего обрыв соединения с базой данных, вместо настоящего соединения можно использовать специальный mock-объект, постоянно выбрасывающий нужное исключение.

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

Моск-объекты удобно использовать:

• если заменяемый объект не обладает необходимым быстродействием;

• заметаемый объект тяжело настраивать;

• нужное поведение заменяемого объекта сложно смоделировать;

• для проверки call-back функций;

• для тестирования GUI.

Например. Есть класс CardChecker, который имеет один публичный метод check, принимающий в качестве параметра класс Card и введенный pin-код, а возвращающий ИСТИНА (в случае, если валидация карты прошла удачно) или ЛОЖЬ (в случае, если pin-код не соответствует данной карте). Внутри данного метода происходит обращение к методу класса CardStore - getPin с параметром Card, который возвращает pin-код данной

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

Рис. 1. Схема взаимодействия между объектами без mock

Для того чтобы протестировать, как класс CardChecker обрабатывает положительный и отрицательный исход валидации, необходимо смоделировать две

ситуации:

• класс CardStore возвращает идентичный заданному pin-код,

• класс CardStore возвращает не равный заданному pin-код.

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

Для того чтобы протестировать метод check класса CardChecker изолированно, необходимо заменить CardStore на некую «заглушку», которая будет возвращать необходимый результат вне зависимости от окружения. Примерная схема подобного взаимодействия изображена на рис. 2.

Так называемая «заглушка» CardStore представляет собой пример мокирования объекта. Она заменила реальный CardStore и работает с CardChecker. При данном подходе во время написания тестов появляется возможность управлять «заглушкой» и указывать явно необходимый результат выполнения метода getPin.

Рис. 2. Схема взаимодействия c mock-объектом

На текущий момент существует несколько библиотек, реализующих mock-тестирование. В Java к наиболее популярным из них можно отнести [2]: jMock, SevenMock, EasyMock, Mockito.

В основе лежит одна идея: замена зависимостей реального объекта виртуальными с помощью создания proxy-класса, имплементирующего тот же интерфейс. Схематично этот принцип изображен на рис. 3.

Рис. 3. Принцип работы mock-библиотеки

Из схемы видно, что mockController имеет доступ к метаданным, описывающим структуру мокируемого объекта. Механизм, который позволяет обращаться к метаданным объектов и динамически их строить, называется reflection. На этом механизме основаны все Java-реализации mock-объектов.

Java Reflection - это механизм, позволяющий осуществлять доступ к коду и динамически менять конструкции кода, используя возможности интерпретатора виртуальной машины, во время выполнения программы [3]. Важнейшими возможностями являются динамическое редактирование и конструирование метаданных классов. То есть в процессе работы программы можно изменять логику работы методов.

Программы, написанные на Java, после компиляции в байт-код исполняются интерпретатором виртуальной машины [3]. Это и позволяет получать необходимую метаинформацию о выполняемом коде и динамически его менять для реализации mock-объектов.

Таким образом, возникает проблема с компилируемыми языками программирования. Нет возможности во время выполнения программы изменять ее код, так как это потребовало бы перекомпиляции.

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

Также существует риск возникновения исключительной ситуации, вследствие того что искомый класс может быть просто не найден (в Java это ClassNotFoundException).

Предлагается способ получения и создания метаинформации не во время выполнения, а на этапе компиляции программы - так называемая пре-генерация кода. Это требует описания всего необходимого для объекта, но позволяет полностью освободить интерпретатор от этой работы. По сути, происходит перекладывание полномочий с интерпретатора на компилятор.

Для примера рассмотрим реализацию этого паттерна в Google Web Toolkit (далее -GWT). Перед разработчиками GWT стояла проблема различной реакции web-приложения

Для решения данной проблемы используется принцип отложенного связывания.

Отложенное связывание (Deferred Binding) - это метод, используемый компилятором GWT для создания и выбора конкретной реализации класса на основе набора параметров [4].

В сущности, отложенное связывание - это GWT-ответ на Java Reflection, позволяющий GWT-разработчикам производить несколько вариантов приложений для разных браузеров и иметь только один из них действительно загруженный и запущенный в браузере.

Браузер клиента

Т

Загрузка запрошенной страницы

Загрузить страницу

_I_

Серверная часть

Ссылка на класс W-

Дай класс для Firefox

GWT генератор

Рис. 4. Принцип работы генератора в GWT

При использовании отложенного связывания есть несколько преимуществ:

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

Принцип работы генератора приведен на рис. 4. На основании данной схемы появляется возможность использовать генератор как замену reflection в реализации mock-объекта.

Часть исходного кода, реализующего mock-объект с помощью пре-генерации, приведена ниже:

public class MockObjectGenerator extends Generator { @Override

public String generate( final TreeLogger logger, final GeneratorContext context, final String typeName ) throws UnableToCompleteException {

JClassType classType;

try {

classType = context.getTypeOracle().getType(typeName); SourceWriter src = createSourceWriter(classType, context, logger); JMethod[] methods = classType.getMethods(); for (JMethod method : methods) {

src.println(getMethodSource(method));

}

src.commit(logger); return typeName + "Generated"; } catch (NotFoundException e) { e.printStackTrace();

}

return null;

}

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

Для того чтобы каким-то образом минимизировать количество ошибок, производится многократное тестирование выпускаемого программного обеспечения различными способами.

В данной статье рассмотрены mock-объекты и преимущества, которые дает их использование, а также проблема их реализации в компилируемых языках программирования.

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

позволяет повысить производительность программы, так как результирующий код не требует никакой дополнительной обработки [5],

повышает такой параметр, как надежность кода, так как все необходимые данные уже известны на этапе компиляции,

• решает серьезную проблему реализации mock-объектов в компилируемых языках программирования.

Данный метод можно применять при тестировании:

• на ранних этапах разработки, когда реализованы только интерфейсы

взаимодействия,

• для ускорения выполнения тестов (изолируя ресурсоемкие компоненты).

Из недостатков предложенного метода можно выделить недостаточную гибкость. Рассмотренная реализация в рамках GWT требует внесения всех мокируемых интерфейсов в конфигурационный файл.

Библиографический список

1. Кент, Бек. Экстремальное программирование: разработка через тестирование / Кент Бек. - СПб. : Питер, 2003. - 224 с. - ISBN 5-8046-0051-6, 0-321-14653-0.

2. Mock Objects [Электронный ресурс] / Сообщество London XP ; ред. Нэт Прайс ; Web-мастер Стив Фримен - Электрон. дан. - Лондон : Великобритания, 2010. - Режим доступа: http://www.mockobjects.com, свободный. - Загл. с экрана. - Яз. англ.

3. Создание корпоративных систем на базе Java 2 Enterprise Edition [Текст] : руководство разработчика : [пер. с англ.] / Поль Дж. Перроун, Венката С. Р. «Кришна», Р. Чаганти [и др.]. - М. : Вильямс, 2001. - 1179 с. ; Перевод изд.: Building Java Enterprise

systems with J2EE / Paul J. Perrone, Venkata S. R. (Krishna), R. Chaganti. Indianapolis. - 5000 экз. - ISBN 5-8459-0168-5 (в пер.).

4. Официальное руководство для разработчиков Google Web Toolkit [Электронный ресурс]. - Режим доступа: http ://code.google. com/intl/ ru-RU/webtoolkit/doc/latest/DevGuide.html.

5. Google Web Toolkit Developer's Guide [Электронный ресурс] / Документация разработчиков Google Web Toolkit ; Web-мастер Google inc. - Электрон. дан. - Маунтин-Вью : США, 2010. - Режим доступа: http://code.google.com/intl/ru-RU/webtoolkit/doc/lat-est/DevGuide.html, свободный. - Загл. с экрана. - Яз. англ.

© Язовский А. С., 2010

Автор статьи - Антон Сергеевич Язовский, аспирант, НОУ ВПО «ОмГА», e-mail: yazovsky@gmail. com.

Рецензент - Э. Б. Хвецкович, кандидат технических наук, доцент, НОУ ВПО «ОмГА».