Подход к тестированию программных интерфейсов приложений мобильных устройств

ПОДХОД К ТЕСТИРОВАНИЮ ПРОГРАММНЫХ ИНТЕРФЕЙСОВ ПРИЛОЖЕНИЙ МОБИЛЬНЫХ УСТРОЙСТВ

К.В. Рубинов

Научный руководитель - д.т.н., профессор A.A. Шалыто

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

Введение

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

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

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

Автором предлагается подход к созданию тестов программных интерфейсов приложений для мобильных телефонов, основанный на спецификациях к интерфейсам и автоматном подходе [1]. При этом на основании спецификаций к интерфейсам описываются и создаются тестовые сценарии, а тестовое приложение создается на основе автоматного программирования.

1. Постановка задачи

Тестирование программного обеспечения (software testing) - деятельность, выполняемая для оценки и улучшения качества программного обеспечения. Эта деятельность в общем случае базируется на обнаружении дефектов и проблем в программных системах [2].

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

Программный интерфейс приложения (Application Programming Interface, API) или интерфейс прикладного программирования - это набор функций, предоставляемый некоторой программной системой для использования ее функциональности в других прикладных программах.

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

1 Функциональное тестирование - проверка соответствия системы предъявляемым к ней требованиям.

При создании программного продукта необходимо обеспечить качество всех его компонент. Поэтому необходимо проводить и тестирование API. Оно должно являться этапом разработки наравне с тестированием программного продукта в целом.

Тестирование API имеет свои особенности, которые будут изложены ниже.

2. Требования к программному интерфейсу приложения

Основным документом, на котором базируется тестирование API, является спецификация программной системы - набор предъявляемых к ней требований.

Для описания программного интерфейса приложения выделяют несколько классов требований:

• требования к данным программного интерфейса (Software Interface Data Requirements);

• функциональные (Functional Requirements) или поведенческие требования (Behavioral Requirements).

2.1. Требования к данным программного интерфейса

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

Приведем пример требований к синтаксису данных для определения протоколов. Пример 1. Требование к синтаксису

"http", "https" протоколы: HTTP Player

Мультимедийный API должен поддерживать ввод локаторов для создания плееров из HTTP/HTTPS соединениякмедиафайлувстандартномсинтаксисе HTTP/HTTPS URL: http://<nyTb к медиа файлу> https://<nyTb к медиа файлу>

В этом требовании задается синтаксис для мультимедийных локаторов:

http://<nyTb к медиа файлу> И https://<путь к медиа файлу>.

2.2. Функциональные (поведенческие) требования

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

Обычно в качестве ключевых слов в описании функциональных требований используются такие конструкции как «должен» (shall) и «если, то» (if..., then).

Исходя из семантики методов, предоставляемых программным интерфейсом приложения, возможны следующие варианты функционирования:

• ввод данных;

• вывод данных;

• переход в состояние;

• получение события/сообщения;

• отправка события/сообщения.

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

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

Пример 2. Ввод данных

public int setLevel

Этот метод должен устанавливать уровень звука для плеера на величину, указанную в параметре level. Этот параметрявляется целым числом в диапазоне 0...100.

Значение ноль должноустанавливать минимальное значение звука - тишина. Значение 100 долж-ноустанавливатьмаксимально еозможныйуровень звука.

Если параметр level имеет отрицательное значение, то уровень звука должен бытьустанов-лен в ноль (silence).

Если параметр level имеет значение больше 100, то уровень звука должен быть установлен 100 (максимально еозможныйуровень звука).

Возвращаемое значение должно представлять новоеустановленное значениеуровня звука.

Когда вызов метода setLevel() заканчивается изменением звука, событие VOLUME_CHANGED должно быть доставлено к зарегистрированному слушателю события PlayerListener. Параметр eventData должен быть VolumeControl-oöbeKmoM. Приложение может использовать этот объект для дальнейшего изменения звука.

В приведенном требовании ввод данных для метода setLevel () обеспечивается через входной параметр level.

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

Пример 3. Вывод данных

public int getState

Данный метод должен возвращать текущее состояние плеера.

Возможныезначения: UNREALIZED, REALIZED, PREFETCHED, STARTED, CLOSED.

Вывод данных обеспечивается через значение, возвращаемое методом

getState () .

Пример функционального требования к методу, обеспечивающему переход в состояние.

Пример 4. Переход в состояние

public void stop

Вызов данного метода для плеера в состоянии STARTED должен остановить проигрывание медиа-файла.

Когда выполнение метода stop () заканчивается, плеер должен перейти в состояние REALIZED.

Вызов данного метода на остановленном плеере (плеер в состоянии UNREALIZED) будет проигнорирован.

Если метод stop () вызван, когда плеер находится в состоянии CLOSED, то должно появиться исключение IllegalStateException.

Вызов метода stop() может обеспечить переход плеера в состояние realized.

Пример функционального требования к методу, обеспечивающему получение/отправку события/сообщения.

Пример 5. Получение/отправка события/сообщения

Когда плеер достигает конца медиа-файла, событие END_OF_MEDIA должно быть доставлено к зарегистрированному слушателю событий PlayerListener. Параметр eventData должен быть java.lang.Long объектом, указывающим время, когда плеер достиг конца медиа-файла.

3. Техники тестирования

Классификация, описанная ниже, применима к процессу тестирования, который базируется на спецификациях программного интерфейса приложения. Техники, базирующиеся на спецификации (Specification-based techniques), разделяются на следующие виды.

1. Positive technique. Тесты строятся с ориентацией на использование тех величин, которые находятся в рамках специфицированных пределов значений. Техника предполагает получение заданных реакций тестируемой системы на допустимые («правильные») воздействия.

2. Negative technique. Тесты строятся с ориентацией на использование тех величин, которые выходят за рамки специфицированных пределов значений, не соответствуют определенному формату или используют искаженные данные. Техника предполагает получение заданных реакций тестируемой системы на недопустимые, некорректные («неправильные») воздействия.

3. Boundary technique. Тесты строятся с ориентацией на использование тех величин, которые определяют предельные или близкие к предельным характеристики тестируемой системы. Данную технику можно выделить как подкласс техники positive.

4. Interaction technique. Тесты строятся с ориентацией на проверку взаимодействия между программными компонентами/модулями, имеющими связи в виде совместных процессов, ресурсов или устройств.

5. Stress technique. Техника является развитием и обобщением четырех техник, описанных выше. Тесты строятся с ориентацией на повышение нагрузки на программную систему, вплоть до достижения предопределенных показателей загрузки и далее на всем протяжении повышения загрузки системы. Примером стрессового тестирования может служить повторяющийся вызов определенного метода с высокой частотой в условиях ограничения ресурсов.

4. Тестирование

4.1. Процедура выбора тестов

Для создания полного и эффективного в использовании тестового набора необходимо подобрать и применить максимально широкий спектр тестов к каждому требованию. Далее рассматриваются возможные варианты соответствия вариантов функционирования и техник тестирования для требований к данным программного интерфейса и функциональных требований. В таблице приведены семь групп функциональных требований и пять техник тестирования. Клетки таблицы с меткой «X» означают, что для определенной группы требований могут быть применимы определенные техники тестирования.

Используемые сокращения: Positive - P; Negative - N; Boundary - B; Stress - S; Interaction - I.

№ группы Требование Тест

P N B S I

1 Ограничение, определение формата (синтаксис) X X

2 Ограничение, определение типа (String, Integer...) X X X

3 Ввод данных X X X X X

4 Вывод данных X X X

5 Переход в состояние X X X X

6 Получение события/сообщения X X X

7 Отправка события/сообщения X X X X

Таблица. Соответствие функциональныхтребований итехниктестирования

Для групп 1 и 2 применимы Р, N и В техники, так как они основаны на контроле данных и не предполагают проверку взаимодействий.

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

Для требований, описывающих вывод данных, по сравнению с вводом, исключаются N и B техники. Вывод данных - ответная реакция системы на определенное воздействие, следовательно, создать условия для применения N и B техник невозможно.

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

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

Группы требований 1 и 2 могут являться общими для остальных групп и проверяться в процессе тестирования групп 3 - 7.

Итак, для выбора тестов необходимо ответить на следующие вопросы.

1. К какой группе относится требование?

2. Какие существуют компоненты, связи, процессы, ресурсы или устройства, смежные с тестируемыми?

3. Какие тесты удобней, легче и выгодней выполнять на используемом оборудовании (автоматические/ручные)?

4. Какое количество тестов даст реалистичные статистические результаты? Дополнительно к описанным выше вопросам необходимо учесть, какие возможны

и/или необходимы предусловия для тестирования.

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

Приведем пример выбора тестов для функционального требования. Пример 6. Функциональное требование

public long setMediaTime

Данный метод должен устанавливать время проигрывания на величину, указанную в параметре newTime. Этот параметр задает новое время в микросекундах.

Возвращаемое значение должно показывать фактически установленное время. Оно может отличаться от величины newTime, так как установка времени может быть не очень точна из-за ограничений платформы.

Если параметр newTime имеет отрицательное значение, тогда время проигрывания будет установлено в ноль (начало медиа-файла).

Если параметр newTime больше, чем продолжительность медиа-файла, тогда время проигрывания должно бытьустановлено на конец медиа-файла.

Время проигрывания может бытьустановлено, если плеер находится в состояниях REALIZED, STARTED.

Еслиметод setMediaTime() вызван, когда плеернаходится всостояниях UNREALIZED или CLOSED, то должнопоявитьсяисключение IllegalStateException.

Проанализировав требование, можно сделать следующие выводы:

• требование является функциональным;

• формат значений определен (long).

В данном примере требование содержит в себе:

• ввод данных через входной параметр newTime метода setMediaTime;

• вывод данных через возвращаемое значение метода setMediaTime;

• получение события/сообщения об исключительной ситуации.

Также в требовании есть зависимость от состояний плеера.

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

1. Positive:

1.1. Проверка установки значения newTime в пределах продолжительности медиа-файла в состояниях realized, started. Ожидается, что возвращаемое значение равно значению параметра newTime с определенной точностью.

1.2. Проверка установки значения параметра newTime на отрицательное значение в состояниях realized, started. Ожидается, что возвращаемое значение равно нулю.

1.3. Проверка установки значения newTime на значение, превышающее продолжительность медиа-файла в состояниях realized, started. Ожидается, что возвращаемое значение равно длительности медиа-файла.

2. Negative:

2.1. Проверка установки значения newTime в состояниях UNREALIZED, CLOSED. Ожидается появление исключения IllegalStateException.

3. Boundary:

3.1. Проверка установки значения параметра newTime на значения: ноль, min_long, max_long. Ожидается, что возвращаемое значение будет соответствовать спецификации, как и в positive группе.

4. Stress:

4.1. Чередование вызовов метода с переходами плеера из состояния в состояние.

4.2. Повторяющийся вызов метода.

5. Interaction:

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

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

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

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

4.2. Сценарное тестирование

Сценарий - подмножество вариантов использования системы или приложения. Тестовый сценарий - последовательность выполнения тестовых процедур.

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

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

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

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

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

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

4.2.1. Выбор тестовых сценариев

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

Существуют следующие разновидности тестовых сценариев.

1. Зависимый тестовый сценарий - в случае нахождения тестом неисправности или ошибки в любом из тестовых случаев тестирование останавливается. Особенности - высокая приоритетность тестовых случаев и сильная зависимость между ними.

2. Независимый тестовый сценарий - в случае нахождения тестом неисправности или ошибки в любом из тестовых случаев тестирование продолжается до конца. Особенности - равнозначность в приоритетах тестовых случаев и слабая зависимость между ними.

3. Комбинированный тестовый сценарий - сочетаются первый и второй принципы. В тестовом сценарии выделяются основная (приоритетная) последовательность, ошибка в которой предполагает окончание тестирования, и второсте-

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

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

Каждый подтест (наименьшая составная часть теста) состоит из начального состояния, ввода и прогнозируемого итога [4]. В идеальном случае, тестовая последовательность должна быть составлена таким образом, чтобы итог и/или конечное состояние одного подтеста являлось вводом и/или начальным состоянием другого (последующего подтеста).

Перед разработчиком тестов стоят задачи выбора и сочетания возможных вариантов тестовых сценариев.

4.2.2. Анализ требований

На данном этапе разработчик тестов для того, чтобы извлечь из требований возможные варианты использования интерфейса приложения, должен «встать на место» того, кто будет использовать API, в общем случае, разработчика приложения.

Пусть, например, в требованиях имеется диаграмма (рис. 1), описывающая возможные состояния и переходы плеера.

Рис.1. Состояния и переходы плеера

В этой диаграмме может быть выделена последовательность вызовов методов, позволяющая осуществить переходы между наибольшим числом состояний плеера: realize

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

Параллельно с анализом диаграммы изучаются другие требования к API. Среди них находятся такие требования, в которых описание методов имеет связь с состояниями плеера. Например, конкретный метод может быть вызван только в определенных состояниях плеера (пример 6).

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

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

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

На простейшем примере было показано, как анализ требований может быть использован для создания тестовых сценариев. К сожалению, любые требования не лишены недостатков и не могут на 100% описать реализуемую функциональность, а тем более возможные варианты ее использования. Это приводит к затруднениям при создании тестов для API, которые могут привести к неполному тестированию функциональности и другим сложностям.

4.3. Тестовое приложение

Разработка тестов для API в итоге сводится к разработке приложения (каркаса), в которое интегрируются тестовые сценарии. Разработчик тестов должен знать язык программирования, в котором реализован API, и учитывать особенности языка при создании приложения.

Тестовые сценарии запускаются из меню приложения в автоматическом режиме или вручную. Результатом выполнения приложения является вердикт: тест прошел -положительный результат (passed), или тест не прошел - отрицательный результат (failed).

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

• универсальность;

• переносимость;

• удобство сопровождения;

• расширяемость.

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

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

Тестовое приложение может находиться в двух состояниях (рис. 2).

1. Idle - исходное состояние приложения с отображением статистики выполнения тестов.

2. Test - выполнение тестов.

В свою очередь, выполнение тестов Test происходит в три этапа.

1. Инициализация ресурсов для выполнения тестового сценария - Init.

2. Выполнение тестового сценария - Run.

3. Очистка выделенных ресурсов - CleanUp.

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

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

^Ji «statennachine» AI : . ..tinguishConfigManager Ol 1 1 «controlledobject» ol : TestCase

O z 1: void {Initialize test case} (j z2: void {Run test case} O z3: void {Cleanup test case}

«eventprovider» pi : TestProvider

if El: String = "el" -¡start... i/ E2: String = "e2" {next...

o2

1 1 «controlledobject» o2 : Statistic

O xO: boolean {All cases run} O zll: void {Show status} 4 z 12: void {Increment passe,,, 0 zl3: void {Increment failed ,,,

Рис. 2. Схема связей автомата

Idle

center /o2.zl 1

el[!o2.x0]

e2[o2,x0]

Test

i^enter / 1 .z...

О

e2[!o2.x0]

el[o2,x0]

r

Рис. 3. Граф переходов автомата

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

Заключение

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

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

Литература

1. Шалыто A.A. Технология автоматного программирования. // Мир ПК. 2003. №10. С. 74-78. http://is.ifmo.ru/works/tech_aut_prog/

2. Орлик C. Программная инженерия. Тестирование программного обеспечения (Software Testing) / Введение в программную инженерию и управление жизненным циклом ПО. 2004. http://sorlik.blogspot.com

3. Интерфейс программирования приложений. http://ru.wikipedia.org/wiki/API

4. Бейзер Б. Тестирование черного ящика. Технологии функционального тестирования программного обеспечения и систем. СПб: Питер, 2004. 318 с.