Объектно-ориентированная среда IBM Rational Functional Tester

Программа Functional Tester позволяет группам тестировщиков реализовать по-настоящему объектно-ориентированную модель автоматизации графического интерфейса пользователя (GUI). Используя иерархическую среду, которая претворяет эту модель в жизнь, тестировщики могут получить огромное преимущество, выражающееся в простоте написания сценариев и простоте обслуживания.

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

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

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

В противоположность инструментам других разработчиков, алгоритм распознавания объектов программы IBM Rational Functional Tester (RFT) является достаточно сложным (что повышает надежность распознавания объектов), оставаясь доступным (через карту объекта, object map). Уникальная схема распознавания объектов в сочетании с поддержкой в RFT языка Java как языка написания сценариев, обеспечивает, в первую очередь, по-настоящему объектно-ориентированный подход к созданию инструментов автоматизации GUI. Этот подход позволяет создавать сценарии на ранней стадии процесса разработки, основываясь на требованиях проекта или спецификации разработчика, вместо того, чтобы ждать, пока приложение не будет полностью написано, а затем перейти к использованию механизма записи-воспроизведения. Кроме того, объектно-ориентированная схема RTF и предлагаемая программой возможность многократного использования кода облегчают обновление параметров распознавания объектов для отражения изменений в соответствующем приложении, не затрагивая других частей кода. Кроме того, при помощи RTF вы можете написать гибкий, многократно используемый Java-код, который будет надежным и простым в обслуживании.

Чтобы наиболее полно использовать это преимущество, группа проектирования качественного программного обеспечения IBM (IBM Quality Software Engineering, QSE) проводит совместную работу со специалистами корпорации по тестированию в целях разработки общей архитектуры RTF. Эта архитектура состоит из трех слоев:

  • Классы «Appobject», которые логически объединяют элементы GUI. Эти классы состоят из дискретных, гранулярных частных карт объектов, которые содержат небольшие количества связанных элементов GUI вместе с подпрограммами, обеспечивающими доступ к этим элементам;
  • Задачи или методы, которые предназначены для выполнения часто используемых путей GUI;
  • Контрольные примеры, которые вызывают задачи, проверяют состояние приложения и фиксируют результаты.

Мы создали пример такой архитектуры, разработав среду, которая состоит из трех папок: appobjects, tasks, and testcases. Каждая из этих папок представляет собой пакет в рамках проекта RTF и представляет один из слоев трехслойной архитектуры. Далее в этой статье по очереди разъясняется назначение каждой папки.

Папка appobjects

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

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

В среде QSE Framework карты объекта размещаются в папке appobjects, которая представляет собой первый слой трехслойной архитектуры данной среды. Задача этой папки заключается в хранении сценариев, которые возвращают объекты GUI в приложении. Каждый сценарий в этой папке включает частную карту объекта и несколько методов, которые просто возвращают объекты для использования другими сценариями.

Для очень простых приложений один сценарий appobjects может соответствовать одной странице в приложении. Например, статическая web-страница может иметь только один сценарий, который в этой карте содержит все объекты и по одному методу на каждый объект, единственной целью которого является возвращение одного объекта на странице. Например, предположим, что вам нужно войти в систему Yahoo, а экран входа в систему состоит из очень простой web-страницы, показанной на рисунке 1 - стандартной web-формы.

Рисунок 1. Страница входа в систему Yahoo
Страница входа в систему Yahoo

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

Листинг 1: сценарий appobjects

public class LoginPage extends LoginPageHelper
{
 public GuiTestObject getText_LoginID() {
 return Text_LoginID(ANY, NO_STATE);
 }

 public GuiTestObject getText_Passwd() {
 return Text_Passwd(ANY, NO_STATE);
 }
 public ToggleGUITestObject getCheckBox__PersistentID() {
 return CheckBox__PersistentID(ANY, NO_STATE);
 }
 
 public GuiTestObject getButton_SignIn() {
 return Button_SignIn(ANY, NO_STATE);
 }
}

Сценарии тестирования, расположенные выше в иерархии среды, в слоях tasks или testcases, теперь могут вызвать написанные вами методы appobjects и получить эти объекты, а затем манипулировать с объектами, чтобы войти в систему приложения.

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

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

Рисунок 2. Почтовый ящик Yahoo
Почтовый ящик Yahoo

Но если вы перейдете по ссылке Inbox (Входящие), то попадете на страницу, показанную на рисунке 3.

Рисунок 3. Папка Входящие почтового ящика Yahoo
Папка Входящие почтового ящика Yahoo

Единственное заметное изменение на данной странице появляется в нижней правой части экрана. Заголовок в верхней части страницы, вкладки, кнопки Check Mail (Проверить почту) и Compose (Написать сообщение), а также элемент Folders Navigator (Папки) остаются неизменными.

Аналогичным образом, если вы перейдете на вкладку Calendar (Календарь), вы увидите экран, показанный на рисунке 4.

Рисунок 4. Календарь Yahoo
Календарь Yahoo 

На этой вкладке вы видите тот же заголовок, связанные с ним ссылки и вкладки, но кнопки и элемент Navigator (Папки) отсутствуют.

Здесь мы сделаем паузу перед тем, как начнем разбивать это приложение по сценариям appobjects, соответствующим каждой странице данного приложения. Проблема заключается в том, что если вы создадите сценарий appobjects для страницы Mailbox (Почтовый ящик), и еще один сценарий для страницы Calendar (Календарь), у вас будет две приватных карты объекта, каждый из которых содержит ссылки для перемещения по вкладкам. Это означает, что при каждом изменении вкладок (например, если разработчик решит использовать кнопки вместо ссылок), вам нужно будет изменить тестовый код в двух местах. Более того, поскольку эти вкладки отображаются на каждой странице данного приложения, то, при использовании упомянутой неправильной стратегии, появляется множество карт объекта, содержащих одни и те же вкладки.

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

На рис. 5 показаны коллекции объектов, которые являются общими для нескольких страниц.

Рисунок 5. Mailbox (Почтовый ящик) Yahoo mailbox c рекомендуемым делением на группы appobjects
Suggested appobjects groupings

Этот анализ показывает, что существует три коллекции объектов, которые являются общими для различных страниц:

  1. Заголовок с вкладками в самой верхней части страницы;
  2. Две кнопки под заголовком;
  3. Элемент навигации в левой части страницы.

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

В итоге для этой страницы мы создадим четыре сценария в папке appobjects:

  • Сценарий HeaderWithMainTabs, отвечающий за заголовок и основной набор вкладок в самой верхней части экрана;
  • Сценарий MailButtons, отвечающий за кнопки;
  • Сценарий MailNavigator для работы со ссылками в левой части экрана;
  • Сценарий WelcomePage, содержащий остальные объекты GUI страницы, которые не используются на других страницах.

Каждый из сценариев должен включать методы, которые возвращают объекты из их карты.

Для примера в листинге 2 показан класс MailButtons.

Листинг 2: класс сценария MailButtons

public class MailButtons extends MailButtonsHelper {

     public GuiTestObject getButton_CheckMail() {
          return Button_CheckMailbutton(ANY, NO_STATE);
     }

     public GuiTestObject getButton_Compose() {
          return Button_Composebutton(ANY, NO_STATE);
     }
     
     public GuiTestObject getButton_SearchMail() {
          return Button_SearchMailbutton(ANY, NO_STATE);
     }
}

После того, как вы разбили первую страницу на отдельные карты объекта, вам следует перейти к другим страницам приложения. Например, переход по ссылке Inbox (Входящие) вызывает отображение нескольких ссылок на отдельные сообщения (см. рисунок 3), но заголовок, кнопки и элемент навигации остаются без изменений. Поэтому все, что вам нужно сделать с этой страницей - это создать еще одну страницу с именем Inbox (Входящие). Затем вы можете продолжить, перейдя на вкладку Addresses (Адресная книга) и вернуться к добавлению сценариев для остальных коллекций объектов и страниц. И, наконец, вы можете создать отдельный сценарий, содержащий кнопки браузера и панели инструментов браузера (Back (Назад), Refresh (Обновить) и так далее), чтобы иметь возможность доступа к этим объектам из любой точки вашего проекта.

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

Примечание: в процессе реализации этой идеи мы обнаружили, что существует большое преимущество в возвращении наших классов стандартных элементов GUI, а не GuiTestObjects или TestObjects. Классы стандартных элементов GUI являются оболочкой интерфейсов TestObject, которые раскрывают и упрощают часто используемые методы.

Папка tasks

Папка tasks представляет собой средний слой трехслойной архитектуры среды QSE Framework. Методы tasks вызывают методы appobjects, чтобы получить доступ к элементам GUI приложения. В свою очередь, методы tasks вызываются контрольными примерами. Достоинствами папки tasks являются предоставление возможности многократного использования кода и защита контрольных примеров от подробностей реализации нижнего уровня. Надежный и тщательно спроектированный уровень tasks наряду с тщательно разработанными картами объекта в слое appobjects, являются критически важными для успеха реализации автоматизации в целом.

Обычно задачи проходят по приложению, тестируя контрольные примеры на соответствие условиям и фиксируя результаты тестирования . Большинство методов tasks практикуют часто используемые пути. Например, для почтового приложения Yahoo! вы, несомненно, сделаете выбор в пользу написания задач для отправки сообщений электронной почты, поиска и открытия сообщений, удаления сообщений и так далее. Другие задачи манипулируют или сложными запросами, или настраиваемыми, нестабильными элементами GUI. Элементы управления календарем Yahoo! - прекрасный пример элементов GUI, которые могут быть необходимы для манипуляций и запросов через задачи.

Создание недостаточного количества задач существенно замедлит написание контрольных примеров, а если при этом не используется преимущество многократного использования кода, то и увеличить затраты ресурсов на обслуживание. И наоборот, написание чрезмерно гранулярных задач является слишком обременительным. Не следует создавать задачу для манипулирования или запроса каждого простого элемента GUI, который присутствует на экране; с тем же успехом можно вызывать напрямую методы слоя appobjects. Проектируя папку tasks, попробуйте действовать с ориентацией на объекты, учитывая и абстрактные (например, почтовые сообщения), и конкретные объекты (например, элементы работы с календарем), требующие внимания.

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

Объединение методов задач в классы должно осуществляться наглядным способом. Может оказаться достаточным написать только четыре класса для согласования страниц Mail (Почта), Addresses (Адресная книга), Calendar (Календарь) и Notepad (Блокнот) Yahoo! Однако, поскольку страницы Mail (Почта) и Calendar (Календарь), вероятно, станут громоздкими и неуклюжими, вам, возможно, захочется переделать класс, чтобы он имел дополнительный уровень детализации. Например, можно разбить класс Mail на такие классы, как MailCompose (для создания и отправки сообщений), MailFolders (для открывания и закрывания папок Inbox (Входящие), Draft (Черновики), Sent (Отправленные) и Trash (Корзина), MailList (для выполнения действий и запросов над списком сообщений), MailAction (для выполнения отключения выбора из меню при нажатии на кнопки и проверки корректности соответствующих строковых ресурсов), и так далее. Для масштабных и сложных приложений может оказаться целесообразным использовать внутри папки tasks вложенные папки для более наглядной организации.

В листинге 3 показан код, реализующий класс MailCompose, содержащий две задачи. Обратите внимание на создание экземпляров классов appobjects MailButtons и ComposeMailPage, а также на то, что эти задачи возвращают логические значения для поддержки контроля над ошибками. Наконец, обратите внимание на то, что одна задача может вызвать другую задачу, что способствует многократному использованию кода и общему снижению количества строк кода.

Листинг 3: код MailCopmose класса MailCompose

public class MailCompose extends MailComposeHelper
{
 MailButtons mailButtons = new MailButtons();
 ComposeMailPage message = new ComposeMailPage();
 
 /**
 * Composes a message in Yahoo mail.
 */
 public boolean composeMessage(String sTo, String sCC, String sBcc, 
 String sSubject, String sBody)
 {
 mailButtons.getLink_Compose().click();
 
 WTextField tfTo = message.getText_To();
 
 if (!tfTo.waitForExistenceBoolean()) {
 logError("Could not create new message. Cannot continue.");
 return false;
 }
 
 tfTo.setText(sTo);
 message.getText_Cc().setText(sCC);
 message.getText_Bcc().setText(sBcc);
 message.getText_Subj().setText(sSubject);
 message.getText_Body().setText(sBody);
 
 return true;
 }

 /**
 * Composes and sends a message in Yahoo mail.
 */ 
 public boolean composeAndSendMessage(String sTo, String sCC,
 String sBcc, String sSubject, String sBody)
 {
 if (!composeMessage(sTo,sCC,sBcc,sSubject,sBody))
 {
 logError("Could not create new message. Cannot continue.");
 return false;
 }
 message.getButton__Sendsubmit().click();
 
 return true;
 } 
}


Папка testcases

Самый верхний слой трехслойной архитектуры QSE Framework - это папка testcases, которая предоставляет самый общий обзор работы по тестированию. Вообще говоря, контрольные примеры вызывают задачи (при необходимости передавая данные), проверяя выполняемость условий и фиксируя результаты. Контрольные примеры должны содержать только простейшую логику и средства передачи управления, все остальное зарезервировано для папки tasks. При недостатке времени и внимания на изучение папки tasks даже не очень опытный программист, вероятнее всего, сможет легко и быстро сгенерировать контрольные примеры.

Действительно, даже от самой надежной папки tasks можно ожидать только описания часто используемых путей приложения. Иногда может возникнуть необходимость прямого вызова метода appobjects каким-либо контрольным примером без вызова задачи. При слишком частом использовании такая практика может быть расценена как проблемная, поскольку обусловливает возрастание сложности контрольных примеров и непомерный объем обслуживания.

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

Код, показанный в листинге 4, реализует SendMail класс, содержащий контрольный пример sendMailWithTextBody. В этом контрольном примере, login - это класс из слоя tasks; обратите внимание на создание его экземпляра, а также на создание экземпляра класса MailCompose. Набор тестов, определенный в классе testMain(), многократно вызывает контрольный пример, передавая в каждом случае различные данные. На протяжении всей процедуры проводится контроль ошибок, и все возможные исключения перехватываются и обрабатываются.

Обычно строковые константы были бы помещены в файл .properties или другой внешний источник данных. Здесь же строки оставлены нетронутыми для иллюстрации примера. Кроме того, при обычных обстоятельствах, класс testcases содержал бы не один, а много контрольных примеров.

Листинг 4: класс SendMail

public class SendMail extends SendMailHelper
{
 /**
 * Data-driven testcase for testing sending mail.
 * Sends mail to addressees and verifies that mail shows up in Sent folder.
 */ 
 public boolean sendMailWithTextBody(String sTo, String sCC, String sBcc,
 String sSubject, String sBody)
 {
 if (!new Login().login())
 return false;
 
 MailCompose message = new MailCompose();
 if (!message.composeAndSendMessage(sTo,sCC,sBcc,sSubject,sBody))
 return false;
 
 if (!message.verifyMessageInSentFolder(sSubject))
 return false;
 
 return true;
 }

 /**
 * Runs a full regression test of this feature area.
 */
 public void testMain (Object[] args) 
 {
 String sTestHeader; 
 
 //Send Mail with Text Body
 sTestHeader = "Send Mail, Text Body, one to: recipient";
 try {
 logTestResult(sTestHeader, sendMailWithTextBody("iristest2004@yahoo.com",
 "", "", "Test one to: recipient", "Hello There"));
 } catch (Exception e) {
 logTestResult("Exception in " + sTestHeader, false, e.getMessage());
 } 
 
 sTestHeader = "Send Mail, Text Body, one to: and one cc: recipient";
 try{
 logTestResult(sTestHeader, sendMailWithTextBody("iristest2004@yahoo.com",
 "iristest2004@yahoo.com", "", "Test one cc: recipient", "Hello There"));
 } catch (Exception e) {
 logTestResult("Exception in " + sTestHeader, false, e.getMessage());
 } 
 
 sTestHeader = "Send Mail, Long Text Body";
 try {
 logTestResult(sTestHeader, sendMailWithTextBody("iristest2004@yahoo.com",
 "", "", "Test long text body", "Lorem ipsum dolor sit amet, consectetur
 adipiscing elit, set eiusmod tempor incidunt et labore et dolore magna
 aliquam."));
 } catch (Exception e) {
 logTestResult("Exception in " + sTestHeader, false, e.getMessage());
 }
 
 //etc.
 
 }
}

Заключение

Действительно полезная, не требующая больших затрат ресурсов на обслуживание функция автоматизации GUI долго была Святым Граалем для тестировщиков. До сих пор ее не так-то просто было добиться. Стандартные методы записи-воспроизведения, рекомендуемые разработчиками программных продуктов, не отличались простотой в обслуживании, а написание и выполнение сценариев вручную ограничивалось недоступностью или чрезмерной простотой технологии распознавания объектов. Но теперь, с появлением программы Rational Functional Tester, вопрос может быть закрыт. Уникальные преимущества RFT предоставляют возможность разработать по-настоящему объектно-ориентированную реализацию автоматизации GUI.

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


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