1. Тарасов В.Б. От многоагентных систем к интеллектуальным организациям. - М.: Эдиториал УРСС, 2002. -352с.
2. Городецкий В.И., Грушинский М.С., Хабалов А.В. Многоагентные системы / Новости искусственного интеллекта, №2, 1998.
3. Городецкий В.И., Карсаев О.В., Конюший В.Г., Самойлов В.В., Хабалов А.В. Среда разработки многоагентных приложений MASDK // Информационные технологии и вычислительные системы, 2003, №12. С.26-41.
4. Pavon J. The INGENIAS Methodology and Tools / J. Pavon, J. Gomez-Sanz Ruben Fuentes // Agent-Oriented Methodologies, Brian Henderson-Sellers & Paolo Giorgini (eds.), Idea Group Publishing, 2005 - P. 236-276.
5. Wеiss G. Multiagent systems. MIT Press, Cambridge, Massachusetts, 1999.
6. Рассел С., Норвиг П. Искусственный интеллект: современный подход. -М.: Вильямс, 2006. -1408с.
7. Greenfield J., Short K. Software Factories: assembling applications with patterns, models, frameworks and tools. Wiley Pablishing, Inc., 2004.
8. Bellifemine F., Poggi A., Rimassa G. Developing multi-agent systems with a FIPA-compliant agent framework // Software - Practice And Experience. - 2001, № 31(2) - P. 103-128
9. Зайцев Е.И. О концепции многоагентных банков знаний, как интеллектуальных обучающих системах // Материалы 16-й международной конференции “Современное образование: содержание, технологии, качество”. В 2-х.т. - СПпб.:Изд-во СПбГЭТУ “ЛЭТИ”. 2010. Т.2. С. 36 - 38.
10. Зайцев Е.И. Распределенная интеллектуальная система на базе программных агентов с нечёткими знаниями // Информационные технологии, №9, 2006.
11. Зайцев Е.И. Методология представления и обработки знаний в распределенных интеллектуальных информационных системах. // Автоматизация и современные технологии. 2008, №1, С.29-34.
УДК 004.054
МАТЕМАТИЧЕСКИЕ МОДЕЛИ ТЕСТИРУЕМОГО ИСХОДНОГО КОДА
Денисов Виктор Сергеевич, аспирант, Саратовский государственный университет им. Н. Г. Чернышевского, Россия, Саратов, denisovenator@,gmail.com
Введение
В данной статье предлагаются ряд формальных понятий и математических моделей для оценки пригодности исходного кода к модульному тестированию в средах JUnit и TestNG. Модульное тестирование было выбрано для анализа, так как оно является важной составляющей современных гибких методик разработки[1]. Модульное тестирование поощряет изменение кода и рефакторинг[2], способствуя общему повышению качества исходного кода.
Вопросы пригодности исходного кода к модульному тестированию хорошо описаны в книге [3] в виде паттернов работы с унаследованным кодом. Однако книга в значительной мере рассчитана на применение описанных методов человеком и не содержит формальных понятий для оценки тестируемости исходного кода. В данной статье развивается идея объектного шва, как наиболее пригодного для сред тестирования Junit и TestNG. В результате были получены понятия внутреннего экземпляра и исходящей зависимости. На их основе был построен ряд математических моделей, которые позволяют оценить, насколько объектноориентированный код пригоден для модульного тестирования.
1. Используемые термины
Будем называть базовыми выражениями языка следующие выражения:
• выражение бинарного оператора;
• выражение унарного оператора;
115
• выражение присваивания;
• выражения приведения типов;
• выражение литерального значения (логического, строкового, числового);
• выражения вызова метода;
• выражение доступа к полю;
• выражение конструирования объекта;
• выражение доступа к массиву;
• выражение конструирования массива;
• выражение получения класса;
• условное выражение.
• Выражение цикла
Данный список неполон и может варьироваться в зависимости от конкретного языка, однако дает общее понятие о базовом выражении языка. Введём несколько определений:
Опр. 1: Выражением будем называть одно из базовых выражений, а также произвольную суперпозицию описанных выше выражений.
Опр. 2: Будем говорить, что выражение S есть подвыражение выражения E, если выражение E есть суперпозиция выражения S и некоторых других выражений.
Опр. 3: Выражение S есть собственное подвыражение выражения E, если S есть подвыражение выражения E и не равно E.
2. Предлагаемые понятия
В работе [4] предлагаются два понятия, характеризующие пригодность метода модульному тестированию и сложность введения метода в средства тестирования:
• внутренний экземпляр класса;
• исходящая зависимость.
Далее детально рассматриваются возможные применения этих идей и дальнейшее их развитие.
3. Внутренний экземпляр класса
3.1. Определения
Определим понятие внутреннего экземпляра.
Опр. 4: Внутренний экземпляр класса - экземпляр класса, созданный оператором конструирования внутри тестируемого метода, либо являющийся результатом вызова метода внутреннего экземпляра.
void method() {
A a = new A();
}
Здесь локальная переменная a является внутренним экземпляром. Пусть есть выражение вида
b = a.<methodCall>*.
Переменная b также будет содержать внутренний экземпляр, если а есть внутренний экземпляр. Не существует возможности изменить характер внешности экземпляра b, если а внутренний экземпляр. Однако если a внешний экземпляр, то он полностью контролируется. Заменяя экземпляр а тестовым двойником [5], можно добиться, чтобы b был произвольным.
Опр. 5: Говорят, что характер внешности b зависит от характера внешности а, если имеет место присваивание b = a.<methodCall>*.
Такое отношение будем называть отношением зависимости характера внешности. Если в качестве вершин взять переменные, которые встречаются в методе, а в качестве отношения смежности взять отношение зависимости характера внешности, то можно построить граф. Рассмотрим пример исходного кода и граф над отношением зависимости характера
116
внешности для этого участка кода.
void method() {
A a = new A();
b = a.getValue().getSomeData(); c = a.getData();
}
Для этого метода граф зависимостей характера внешности представлен на рисунке 6.
Рис. 6 - Граф зависимостей характера внешности
3.2. Временная составляющая
В реальном исходном коде переменной могут присваиваться разные значения в разные моменты времени. Это осложняет анализ структуры графов зависимостей характера внешности. Из одной переменной может идти несколько дуг. По одному пути переменная может быть внутренним экземпляром, по другому - внешним. Рассмотрим следующий участок кода и иллюстрацию.
void method(X x) {
A a = new A();
b = a.getValue().getSomeData(); a = x.getData();
}
Рис. 2 - Случай повторного присваивания
Из рисунка 2 видно, что граф содержит неоднозначность. В разные моменты времени a имеет разные характеры внешности. Для решения данной проблемы предлагается приводить метод к SSA форме или форме единственного присваивания.
Таким образом если привести тестируемый метод к SSA форме[6], то можно построить граф зависимостей характера внешности и анализ временной составляющей не будет представлять труда. Определим граф внутренних экземпляров следующим образом.
Опр. 6: Граф внутренних экземпляров - граф зависимостей характера внешности, построенный над SSA формой метода.
Понятие внутреннего экземпляра позволяет сформулировать достаточное условие тестируемости метода.
Опр. 7: Для того чтобы метод был тестируем достаточно, чтобы число внутренних экземпляров было равно нулю.
И действительно, если метод имеет нулевое количество внутренних экземпляров, то все экземпляры классов, с которыми работает метод являются внешними и таким образом легко симулировать внешнее окружение, используя тестовые двойники (Test Double) [5]. Метод, удовлетворяющий достаточному условию тестируемости, будем называть абсолютно тестируемым методом.
Опр. 8 : Метод абсолютно тестируем, если число внутренних экземпляров равно нулю.
Понятие внутреннего экземпляра дает иное, более формальное определение объектного шва. Такое определение позволяет использовать его для автоматического поиска швов и дальнейшего наглядного представления.
3.3. Категория заменяемости
117
Не всякий внешний экземпляр может быть заменяем. Поэтому также важна категория заменяемости. Важно рассматривать граф зависимостей характера внешности в пределах всего класса. Экземпляры могут зависеть от экземпляров следующего типа:
• локальные переменные;
• аргументы метода;
• поля класса;
• статические поля других классов;
• статические методы других классов (по сути глобальные поля и методы).
Наиболее легко заменяемы аргументы метода. Заменяемость полей класса разнится в
зависимости от их модификатора видимости. Поля с модификатором видимости public могут быть выставлены прямо перед вызовом тестируемого метода. Чуть более сложны в замене protected поля, но для их прямой установки можно воспользоваться паттерном модульного тестирования Test Specific Subclass[5]. Наиболее сложны в замене private поля. Для анализа их характера внешности требуется поиск пути от данного поля до аргумента метода или конструктора в графе внутренних экземпляров.
Граф внутренних экземпляров некоторого класса может выглядеть следующим образом.
Рис. 3 - Граф внутренних экземпляров класса
На рисунке 3, овалом methodB_v обозначены аргументы метода. Прямоугольники - методы.
Опр. 9: Будем называть экземпляр A гарантированно внешним, если A находится в аргументах метода, либо характер внешности экземпляра A зависит от характера внешности экземпляра B. При этом B есть гарантированно внешний экземпляр
Гарантированно внешние экземпляры попадают в тестируемый класс через аргументы методов и конструкторов. Обращение к статическим полям или методам имеет достаточно ограниченную заменяемость: если для статических полей можно использовать паттерн Supersede Instance Variable[3], то для подмены возвращаемого значения статического метода требуется значительно больше усилий и этот процесс плохо формализуем, в каждом конкретном случае приходится действовать, исходя из конкретных обстоятельств.
3.4. Квантификаторы характера внешности
В связи с наличием в программах операторов ветвления, характер внешности может зависеть от условий, которые встречаются в операторах ветвления или цикла. В связи с этим предлагается ввести квантификаторы характера внешности. Квантификатор - это условие, которое показывает, когда экземпляр будет внешний или внутренний.
4. Исходящая зависимость
4.1. Определения
В отличие от внутренних экземпляров, исходящие зависимости - это классы, экземпляры которых требуются методу для работы, но не обязательно созданы внутри метода. Рассмотрим следующее определение.
Опр. 10: Говорят, что выражение E имеет тип A, если в результате вычисления выражения E результат имеет тип A.
Пусть, например, класс A содержит метод getB, имеющий тип возвращаемого значения B. Тогда выражение a.getB имеет тип B, где а имеет тип A.
118
Рассмотрим следующий пример.
void method(A a) { a.getB()
}
В данном примере исходящими зависимостями являются классы A и B.
Опр. 11: Класс A есть исходящая зависимость метода M, если существует выражение Е, принадлежащее M, такое, что его тип есть A.
Заметим, что возвращаемое значение метода getB() может быть null, и это никак не повлияет на работоспособность метода. Метод не обращается к внутренней структуре возвращаемого значения, тогда как a null быть не может, что требует от создателя теста на метод method подачи ненулевого значения переменной a. Такие зависимости назовем существенными.
Опр. 12: Класс A есть существенная исходящая зависимость метода M, если A -исходящая зависимость метода M и есть обращение к полям или методам A.
В отличие от внутренних экземпляров, количество исходящих зависимостей не может быть нулем. Так или иначе, метод должен взаимодействовать с окружающей средой. Однако предполагается, что число различных исходящих зависимостей не должно превышать некоторого порогового значения. Исходящие зависимости метода образуют множество исходящих зависимостей метода. У правильно спроектированного метода, соблюдающего принцип единственной ответственности, множество исходящих зависимостей логически связанно или, другими словами, обладает высоким зацеплением [7].
Опр. 13: Множество исходящих зависимостей метода M - множество классов A таких, что A есть исходящая зависимость метода M.
4.2. Граф исходящих зависимостей
Для наглядного представления исходящих зависимостей внутри проекта предлагается строить граф исходящих зависимостей. В отличие от графа связности (coupling), граф исходящих зависимостей отражает не наличие знания одного класса о другом, а требование существования экземпляра. Дуга между классом А и классом B существует тогда, когда существует такой метод M класса A, что исходящая зависимость метода M есть класс B.
Выводы
Введенные понятия оказывают существенную помощь при оценке пригодности кода к модульному тестированию. Формальность описанных критериев позволяет реализовать автоматический подсчет внутренних экземпляров и исходящих зависимостей. Наряду с метриками, предложенными в [8,9], они позволяют опосредованно оценивать состояние проекта. На основе описанных понятий разрабатывается приложение для автоматизации подсчета внутренних экземпляров, исходящих зависимостей и построения соответствующих графов. Приложение работает с кодом языка Java и реализовано в виде цели системы сборки Ant.
Литература
1. Бек К. Экстремальное программирование. СПб: Питер, 2002. 224 р.
2. Мартин Фаулер. Рефакторинг. Улучшение существующего кода. СПб: Символ-плюс, 2009.
3. Майкл Физерс. Эффективная работа с унаследованным кодом. М: Вильямс, 2009.
4. Виктор Денисов. Критерий тестируемости исходного кода. // RSDN Magazine. 2010. № 2.
5. Джерард Месарош. Шаблоны тестирования xUnit. СПб: Символ-плюс, 2009.
6. Bilardi G., Pingali K. The Static Single Assignment Form and its Computation. 1999.
7. Stevens, W.P. Structured design // IBM Systems Journal. 1974. Vol. 13, № 2. P. 115-139.
8. McCabe T.J. A Complexity Measure // Software Engineering, IEEE Transactions on. Vol. 2, № 4. P. 308-320.
9. Chidamber S.R., Kemerer C.F. A metrics suite for object oriented design // IIEEE Trans. Software Eng. 1994. Vol. 20, № 6. P. 476-493.
119