Эффективные методы автоматизации тестирования в Rational Functional Tester

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

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

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

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

Примечание:
При написании этой статьи автор использовал следующее программное обеспечение:

  • IBM® Rational® Functional Tester версии 7.0.0;
  • Microsoft® Internet Explorer® версии 6.0.2900.2180, SP2;
  • Операционную систему Microsoft® Windows® XP Professional, SP2;

Альтернативные способы поиска объектов и их свойств

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

Запрос и настройка значений свойств объектов

Возникало ли у вас когда-либо желание динамически в процессе выполнения программы сравнить предыдущий вариант значения с текущим значением? А может быть, вам хотелось добавить в сценарий Rational Functional Tester переход, основанный на текущем значении свойства, содержащегося в каком-либо объекте? Извлечь значение свойства можно программным путем посредством вызова метода getProperty.

В примере из листинга 1 метод getProperty используется для того, чтобы определить, содержит ли метка сообщение об успешном выполнении. Если содержит, то будет нажата кнопка OK . Если нет, то будет нажата кнопка Cancel .

Листинг 1: Использование метода getProperty

                
if("SUCCESS".equals(dialog_htmlDialogStatic().
getProperty(".text")))
{
dialog_htmlDialogButtonOK().click();
} 
else 
{
dialog_htmlDialogButtonCancel().click();
}

Если нужно узнать, какими свойствами обладает некоторый объект, можно открыть карту тестовых объектов Test Object Map и просмотреть перечисленные в ней свойства. (См. рисунок 1.)

Рисунок 1. Свойства в карте тестовых объектов
Рисунок 1. Свойства в карте тестовых объектов

Кроме того, можно просмотреть доступные свойства, записав временную точку верификации (verification point, VP) свойств объекта или вставив команду для извлечения значения свойства в переменную при помощи мастера VP and Actions.

Примечание:
Rational Functional Tester также поддерживает метод setProperty. Однако этот метод не дает гарантии результата: Не пользуйтесь им, если не уверены в результате. Причина заключается в том, что метод setProperty вызывает внутренние методы, которые могут нарушить целостность тестируемого приложения.

Теперь, когда вы знаете, как получить свойства объектов, вы можете задать вопрос: "А как можно найти сам объект?" Хороший вопрос.

Способы поиска тестовых объектов

Основной компоновочный блок сценария Rational Functional Tester - это постоянно используемый тестовый объект, TestObject .TestObject представляет собой точку соединения между воспроизводимым сценарием и тестируемым приложением. Каждому TestObject в сгенерированном сценарии тестирования соответствует объект в приложении, на базе которого ведется запись сценария, и этот объект теперь присутствует и в карте тестовых объектов Test Object Map.

Скорее всего, вы обычно взаимодействуете с тестовыми объектами TestObject с использованием карты объектов. Однако Rational Functional Tester поддерживает также средства для программного поиска TestObject. Поиск ведется по паре имя-значение, определяющей свойства TestObject или TestObjects, которые нужно найти. Поиск может быть глобальным или ограничиваться потомками родительского узла TestObject.

Rational Functional Tester использует объект с именем RootTestObject для глобального представления тестируемого приложения.

  • Если вы хотите выполнить поиск по всему приложению, вызовите поисковый метод для RootTestObject.
  • Если нужно найти конкретный объект, просто вызовите поиск для этого TestObject. Поиск по конкретному TestObject найдет только дочерние объекты этого TestObject

Марк Новацки (Mark Nowacki) и Лиза Нодвелл (Lisa Nodwell) написали статью о правильном понимании и использовании метода TestObject.find (см. второй листинг в разделе Ресурсы). Я не привожу свои примеры кода, чтобы вы могли познакомиться с кодом, написанным этими авторами. Они проделали большую работу, объяснив и проиллюстрировав теоретические принципы на практических примерах.

Решение проблемы неточного распознавания объектов

Время от времени Rational Functional Tester не может различить два объекта, которые вели себя похожим образом при воспроизведении сценария. Чаще всего это происходит в том случае, если одновременно открыты два браузера или два экземпляра одного приложения. Если запущены два Web-браузера, то Rational Functional Tester пытается разрешить неоднозначность, используя якорь для определения целевого объекта. Теперь вы знаете, как использовать поисковый метод, и можете идентифицировать экземпляры браузера или приложения при помощи ссылки на TestObject.

Одновременный запуск нескольких экземпляров приложения во время воспроизведения сценария ведет к неоднозначности определения цели таких команд, как object() или click(). Чтобы разрешить эту неоднозначность, можно воспользоваться ProcessTestObject при вызове команды startApp. В примере из листинга 2 ProcessTestObject действует как якорь, помогающий найти нужное приложение.

Листинг 2: Использование ProcessTestObject для привязки приложения

                
ProcessTestObject pto1 = startApp("ApplicationOne");
ProcessTestObject pto2 = startApp("ApplicationTwo");
object(pto1, DEFAULT).click();

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

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

Rational Functional Tester удаляет регистрацию ограниченных ссылок только после завершения выполнения всего теста, а не одного конкретного сценария. Пока существует ограниченная ссылка на объект, Rational Functional Tester может не допустить полного освобождения объекта в приложении. Например, пока вы сохраняете ограниченную ссылку на Java™-объект, этот Java-объект не считается потерявшим актуальность и подлежащим удалению. Поэтому мы рекомендуем явно удалить регистрацию всех созданных поисковых ссылок сразу после того, как они станут ненужными.

Класс RationalTestScript содержит несколько методов, удаляющих ссылки на тестовые объекты TestObjects:

  • com.rational.test.ft.script;
  • RationalTestScript.unregister;
  • unregisterAll.

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

Способы решения распространенных проблем с браузерами

Ниже перечислены некоторые распространенные проблемы, с которыми можно встретиться при тестировании HTML-приложений

Устранение нежелательного поведения при помощи метода .readystate

Если состояние вашего браузера или объектов в браузере не соответствует ожидаемому, можно столкнуться с нежелательным (странным, непредсказуемым) поведением при попытке взаимодействия с браузером или объектами, особенно если много взаимодействий выполняется не в рамках вспомогательных методов. Именно поэтому проверка состояния готовности readyState Web-браузера или какого-либо из объектов должна стать привычным делом.

Значения readyState в Rational Functional Tester

Значение Состояние Описание
0 uninitializedObject Объект не инициализирован данными
1 loadingObject Объект в состоянии загрузки данных
2 loadedObject Объект завершил загрузку данных
3 interactiveUser Пользователь может взаимодействовать с объектом, даже если он загружен не полностью
4 completeObject Инициализация объекта завершена

Если вы знаете, что предстоит взаимодействие с большой таблицей, деревом (каталогом файлов) или HTML-документом, стоит проверить состояние этих объектов (Листинг 3) до начала взаимодействий.

Листинг 3. Проверка состояния готовности readyState

                
  while 
  (Integer.parseInt(object.getProperty(".readyState").toString())
  < 4) 
  {
  sleep(2);
  }

Улучшение исполнения теста при помощи метода waitForExistence

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

  1. В процессе записи сценария запустите приложение;
  2. Нажмите кнопку Insert Verification Point or Action Command на панели инструментов Recording;
  3. На странице выбора объектов Select an Object мастера Verification Point and Action Wizard нажмите левой кнопкой мыши на значке Object Finder и перетащите его на HTML-страницу (не просто в область окна браузера, а именно на страницу);
  4. Нажмите кнопку Next;
  5. На странице выбора действий Select an Action мастера Verification Point and Action Wizard установите флажок Wait for Selected TestObject;
  6. Если нужно, снимите флажок для Use the defaults, чтобы изменить параметры максимального времени ожидания Maximum Wait Time и интервала проверок Check Interval, которые равны соответственно 2 минутам и 2 секундам;
  7. Нажмите кнопку Finish.

Однако вам, возможно будет проще самостоятельно добавить вызов после команды startApp. Все, что вам придется сделать - это добавить ссылку на тестовый объект BrowserTestObject и вызов метода waitForExistence.

Обработка незапланированных активных окон

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

Впрочем, в справочной системе Rational Functional Tester описаны два эффективных решения (одно простое, другое посложнее). Одно из решений - воспользоваться классической методикой try-and-catch (Листинг 4) и дождаться появления сообщения. Если сообщение не появится, можно продолжать.

Листинг 4. Ожидание всплывающего диалогового окна

                
  try 
  {
  // Dialog_HtmlDialogButtonOK().waitForExistence(5,1);
  Dialog_HtmlDialogButtonOK().click();
  }
  catch(ObjectNotFoundException e) 
  {
  }

Совет:
Если ожидание должно длиться определенное время, можно удалить из кода строку после символа комментария.

Еще одно решение, требующее чуть больше усилий - это реализация простой проверки, аналогичной проверке из исключения onObjectNotFound. Включив эту реализацию во вспомогательный суперсценарий, можно обрабатывать события для любого сценария Rational Functional Tester, являющегося расширением этого вспомогательного суперкласса (подробнее об этом далее в этой статье).

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

Кроме точек верификации, определяемых во время записи, в сценарий тестирования Rational Functional Tester можно включить и дополнительные точки верификации (и не только с помощью команды Insert at Cursor). Включение в сценарий точек верификации вручную и динамически позволяет определить данные для сравнения по объекту, который не включен в карту тестовых объектов.

Точки верификации, добавляемые вручную

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

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

Листинг 5. Использование метода vpManual

                
  vpManual
  ("ManualVP_01", "Check something manually.").performTest();
  // или
  vpManual
  ("ManualVP_01", "Check something manually.", 
  "Check something manually.").performTest();

При первом выполнении точки верификации, добавленной вручную, если объект точки верификации еще не существует, будет передано базовое значение (которое затем можно просмотреть и изменить в Rational Functional Tester, как и значение любой другой точки верификации). В файле журнала будет написано: Created verification point baseline.

Начиная с этого момента, все последующие вызовы метода vpManual для этой точки верификации будут сравнивать актуальную точку с базовой. Как видно из листинга 5, метод vpManual можно вызвать, передав ему оба результата - базовый и актуальный. В этом случае объект точки верификации в Rational Functional Tester игнорируется.

Динамические точки верификации

Иногда возникает необходимость в выполнении точки верификации в тестовых объектах, не включенных в карту объектов. С этой целью можно использовать динамические точки верификации при помощи метода vpDynamic (листинг 6). Динамические точки верификации воспроизводят соответствующий пользовательский интерфейс при следующем прогоне сценария. Можно вставить данные точки верификации, протестированные для объекта, указанного сценарием. В этом случае вам не придется вручную воспроизводить тест до соответствующего состояния, прежде чем вы сможете записать точку верификации.

Если вы передаете сценарию только имя точки верификации, то при следующем воспроизведении этого сценария будет активирован мастер записи точек верификации Recording Verification Point and Action Wizard . С помощью этого мастера можно задать тестовые объекты TestObject и базовые данные для последующих выполнений теста.

Листинг 6. Использование метода vpDynamic

                
  vpDynamic
  ("DynamicVP_01").performTest();
  // или
  vpDynamic
  ("DynamicVP_01", TestObjectHere()).performTest();

Предостережение:
Второй пример из листинга 6 требует передачи сценарию актуального тестового объекта TestObject. Хотя указанный TestObject не включен в карту тестовых объектов, он постоянно должен быть одним и тем же объектом, чтобы результаты имели смысл. Поэтому еще раз повторяю: пользуясь методом TestObjects, будьте внимательны.

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

Подробно об использовании низкоуровневых команд

Низкоуровневое воспроизведение эмулирует точные перемещения мыши и манипуляции с клавиатурой, выполняемые пользователем. Такое воспроизведение сценариев позволяет более точно управлять отдельными действиями пользователей, например, в программах для векторного рисования (черчения), эмуляторах PDA и других нетрадиционных инструментах, учитывающих свойства объектов, которые совсем не похожи на обычные команды click и input.

Например, предположим, что вы тестируете распознавание ручного ввода в эмуляторе VTech Helio Emulator, который показан на рисунке 2.

Рисунок 2: Эмулятор VTech Helio Emulator
Рисунок 2.  VTech Helio Emulator

Традиционные сценарии Rational Functional Tester в приложениях, подобных Helio Emulator, малоэффективны. Фактически, как я писал в предыдущей статье о применении низкоуровневых сценариев в IBM® Rational® Robot (см. раздел Ресурсы), почти единственным выбором для таких приложений остается низкоуровневая запись. Перейдя на низкий уровень, вы сможете воспроизвести отдельные компоненты щелчка мышью.

Класс RootTestObject содержит два низкоуровневых метода:

  • emitLowLevelEvent(LowLevelEvent)
  • emitLowEvent(LowLevelEvent[])

Ниже приводится список методов для конструирования низкоуровневых событий LowLevelEvents в фабрике SubitemFactory:

  • delay(int) Примечание: в миллисекундах
  • keyDown(string)
  • keyUp(string)
  • mouseMove(point)
  • mouseWheel(int)
  • leftMouseButtonDown()
  • leftMouseButtonUp()
  • rightMouseButtonDown()
  • rightMouseButtonUp()
  • middleMouseButtonDown()
  • middleMouseButtonUp()

Код сценария, представленный в листинге 7, рисует на блокноте распознавания ручного ввода для Helio в Microsoft® Paint®.

Листинг 7. Использование низкоуровневых сценариев в Rational Functional Tester

                
  afx10000008window().click(atPoint(100,100));
  LowLevelEvent llEvents[] = new LowLevelEvent[7];
  llEvents[0] = mouseMove(atPoint(100,100));
  llEvents[1] = leftMouseButtonDown();
  llEvents[2] = delay(250);
  llEvents[3] = mouseMove(atPoint(105,120));
  llEvents[4] = delay(250);
  llEvents[5] = mouseMove(atPoint(110,100));
  llEvents[6] = leftMouseButtonUp();
  getRootTestObject().emitLowLevelEvent(llEvents);

Код, представленный в листинге 7, генерирует в окне документа программы букву V как показано на рисунке 3.

Рисунок 3: Рисование при помощи Microsoft Paint в эмуляторе Helio
Рисунок 3: Рисование при помощи Microsoft Paint в эмуляторе Helio (фото)

Есть ли недостатки у этой грандиозно эффективной функции? Насколько я знаю, в отличие от Rational Robot, весь этот код вам придется писать вручную. Мне не известен способ переключения на низкоуровневую запись в Rational Functional Tester. Но и описанного вполне достаточно. Если вы действительно тестируете программу типа Helio, вам все равно придется создать методы многократного использования для написания букв. Поэтому, вероятнее всего, вам нужно будет разобраться со всеми буквами всего один раз.

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

Улучшение сценариев при помощи вспомогательного суперкласса

Если вы не читали статью Денниса Шульца (Dennis Schultz) "Creating a super helper class in IBM Rational Functional Tester," (Создание вспомогательных суперклассов в IBM Rational Functional Tester), перейдите к разделу Ресурсы и прочтите ее сейчас. Эта статья - самый лучший ресурс для изучения того, как работает суперкласс, из всех, которые мне приходилось видеть. Вспомогательные классы помогают добавить функциональности вашим сценариям тестирования.

По умолчанию, все сценарии Rational Functional Tester представляют собой расширения класса RationalTestScript и поэтому наследуют ряд методов (таких как callScript). Более опытные тестировщики могут предпочесть создание собственных вспомогательных суперклассов, чтобы расширить класс RationalTestScript, добавив в RationalTestScript собственные методы или заменив существующие.

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

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


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=8262