Разделы портала

Онлайн-тренинги

.
Введение в автоматизированное тестирование с использованием Mercury QuickTest Pro в вопросах и ответах
02.10.2008 13:58

Автор: Михаил Давыдов, Luxoft Company (www.luxoft.com)

В материале рассматриваются вопросы, которые чаще всего возникают при первом знакомстве с инструментом автоматизации функционального и регрессионного тестирования Mercury Interactive — QuickTest Pro.

В статье обсуждается работа с тремя версиями QTP — 6.5, 8.2 и 9.0. Если это не оговаривается специально, ответы на вопросы подходят для всех трёх версий.

  • Actions, Iterations
  • Использования объекта DataTable и параметризация
  • Логгинг
  • Распознавание объектов в QTP
  • Работа с Object Repository
  • Методы Test Object
  • Синхронизация
  • Свойства Объектов
  • Работа с библиотеками и программирование на VBScript
  • Использование объекта Environment
  • Запуск пакетов тестов и использования QTP Automation Object Model
  • Undocumented features

Краткая аннотация:

В этой статье я попробую ответить на вопросы, которые чаще всего возникают при первом знакомстве с инструментом автоматизации функционального и регрессионного тестирования Mercury Interactive — QuickTest Pro.

В статье обсуждается работа с тремя версиями QTP — 6.5, 8.2 и 9.0. Если это не оговаривается специально, ответы на вопросы подходят для всех трёх версий.

Отмечу впрочем, что почти все вопросы, рассматриваемые в статье, освещены в Help, a многие ответы ранее уже публиковались на форуме проекта Software-Testing.Ru


Actions, Iterations

Вопрос: Что такое Action?
Вопрос: Что такое Reusable Action?

Использования объекта DataTable и параметризация

Вопрос: Что такое Data-driven тестирование? Как параметризировать тест?
Вопрос: Что такое Run-time data sheet?
Вопрос: Как приступить к параметризации, с чего начать?
Вопрос: Какие существуют ограничения на использование DataTable?

Логгинг

Вопрос: Что записывается в лог QTP, и можно ли это настроить?

Распознавание объектов в QTP

Вопрос: При воспроизведении записанного теста, QTP не распознаёт объекты. Почему? Что делать?
Вопрос: Как правильно настроить распознавание объектов в QTP с помощью настроек Object Identification?
Вопрос: Что такое Smart Identification?
Вопрос: Можно ли распознавать объекты интерфейса без использования Object Repository?
Вопрос: Что делать, если элемент интерфейса тестируемого приложения распознаётся как "WinObject", несмотря на то, что является более специализированным элементом (таким как кнопка, drop-down list, edit box, и т.п.

Работа с Object Repository

Вопрос: Объекты типа Page/Frame дублируются в Object Repository при записи скрипта. Почему?
Вопрос: В каких случаях QTP создаёт новые объекты в Object Repository (настройка Web settings?)
Вопрос: Чем отличается тип репозитория Shared от per Action?
Вопрос: Каким образом свойства распознавания объектов в OR могут поменяться?
Вопрос: Можно ли отказаться от использования Object Repository? Как?

Методы Test Object

Вопрос: Как получить доступ к дочерним объектам (если мы не знаем их свойств)?
Вопрос: Что такое свойство object?

Синхронизация

Вопрос: Тест не дожидается появления/отрисовки объекта, сообщает об ошибке и переходит к выполнению следующих операторов (также с ошибками). Как сделать так, чтобы QTP дожидался появления объектов либо их определённого состояния (например, enabled)?

Свойства Объектов

Вопрос: Чем отличаются TO Property, RO Property и Run-time object property?

Работа с библиотеками и программирование на VBScript

Вопрос: Что такое библиотека функций? Как подключить библиотеку?
Вопрос: В чём отличие подключения библиотеки в разделе Test Settings>Resources от использования функции ExecuteFile()
Вопрос: Как использовать классы в библиотеках?
Вопрос: Как использовать функции, определенные в DLL?
Вопрос: Как работать с объектами COM/ActiveX?
Вопрос: Можно ли редактировать библиотеки?

Использование объекта Environment

Вопрос: Зачем нужен объект Environment?

Запуск пакетов тестов и использования QTP Automation Object Model

Вопрос: Как запустить тест/набор тестов из командной строки?

Undocumented features

Вопрос: Можно ли использовать HTML в логах?


Actions, Iterations

Вопрос: Что такое Action?

Ответ:

Action — это независимый скрипт в составе теста. Он имеет свой контекст имен переменных, свой локальный Object Repository (хранилище описаний объектов пользовательского интерфейса тестируемого приложения), свой Action Sheet (называемый, также Local Sheet — таблица для хранения значений параметров; его можно вызывать из других тестов. Кроме того, начиная с QTP 8.0 у Actions есть свои параметры (не путать с Data Table parameters: в данном случае имеются в виду значения переменных, передающихся в action извне, либо выходные параметры, аналогично параметрам функций).

В свойствах Action можно указать, сколько раз подряд его надо запустить (количество итераций) — это имеет смысл делать при активном использовании параметризации. При использовании параметризации, при каждой следующей итерации Action, все локальные параметры принимают новое значение — значение из ряда Action Sheet, совпадающего с номером итерации. Следует иметь в виду, что кроме Action Sheet, существует Global Sheet (один на весь тест) — значения параметров, описанные в нём, изменяются при переходе к следующей итерации теста, а не Action.

В Mercury считают, что один Action должен примерно соответствовать одной бизнес операции, или одному Use Case. То есть, использование Actions (по Mercury) — основной способ функциональной декомпозиции. В реальности, вместо Actions для этих целей часто бывает удобнее использовать функции. Впрочем, это зависит от стиля Ваших тестов, в частности, от того, используете ли Вы параметризацию.

Вопрос: Что такое Reusable Action?

Ответ:

Для вызова Action из другого теста (либо из другого Action) необходимо, чтобы в свойствах action (Action Properties) была выставлена галочка "Reusable action".

Вопрос: Какие есть способы передачи значений переменных между разными Actions?

Ответ:

Каждый Action имеет свой контекст имён, поэтому переменные одного Action не видны из другого. Универсальный способ передачи переменных, начиная с версии QTP 6.0 — использование объекта Environment. Кроме того, начиная с версии 8.0 у Actions появились параметры (см. Help: Action properties, Action call properties, Action parameters). То есть, Action, — это в некотором смысле аналог функции с входными и выходными параметрами.

Использование объекта DataTable и параметризация

Вопрос: Что такое Data-driven тестирование? Как параметризировать тест?

Ответ:

Для того, чтобы вместо фиксированных значений параметров функций (например, текста, вводимого в поле ввода) использовать (в цикле) значения из таблицы, используется подход, называемый Data-Driven тестирование. При параметризации, исполнение теста происходит в форме исполнения двух вложенных циклов — по всему тесту целиком и по отдельным Actions. Соответственно, есть 2 типа параметров: глобальные — для всего теста, и локальные — для отдельных Actions. В начале каждой итерации все параметры приобретают значения, хранящиеся в строчке соответствующей таблицы (Global Sheet/Action Sheet), номер которой равен номеру итерации (теста или Action соответственно).

Вопрос: Что такое Run-time data sheet?

Ответ:

Кроме использования Data Table для хранения входных тестовых данных (параметры), QTP позволяет использовать его для хранения выходных данных (Output Values). Во время выполнения теста, значения в Data Table можно менять, однако они не будут сохранены в тесте. Зато их можно будет увидеть в отчёте об исполнении теста (логе).

Вопрос: Как приступить к параметризации, с чего начать?

Ответ:

Два самых удобных способа:

  • Из Keyword View (кликнуть на параметр функции, который хотите параметризировать) — появится кнопочка. Кликнуть — откроется диалог.
  • Tools>Data driver

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

Вручную это делается так:

1. В соответствующей таблице (Local Sheet или Global Sheet):
          a. DoubleClick на заголовке неиспользуемого столбца — вводим имя параметра
          b. Вручную заполняем ряды
2. Для использования параметра в скрипте, в качестве параметра функции или метода используем (MyParam — имя параметра):

DataTable("myParam",dtGlobalSheet) — для глобальных параметров (параметров теста)
DataTable("myParam",dtLocalSheet) — для локальных параметров (параметров Action)

 

Вопрос: Какие существуют ограничения на использование DataTable?

Ответ:

Во время исполнения нельзя добавлять дополнительные ряды в таблицу. Кроме того, использование большого количество параметров и/или рядов заметно влияет на производительность. Поэтому DataTable рекомендуется использовать только по прямому назначению — для параметризации и хранения Output Values (Хотя существует развитый API для работы с таблицами — cм. Help по объектам: DataTable, Sheet, Parameter).

Логгинг

Вопрос: Что записывается в лог QTP, и можно ли это настроить?

Ответ:

Записываются все действия над тестовыми объектами (то есть, все statements, полученные во время записи теста) и сообщения об ошибках. Flow Controls statements, вызовы пользовательских функций и т.п. не записываются. Это — то, что QTP пишет в лог, если запись в лог не контролировать программно. Для работы с логом служит встроенный объект Reporter. У него есть всего один метод — ReportEvent() и одно свойство — Filter. Для записи в лог своего собственного сообщения (например, комментария или сообщения об ошибке), используется метод ReportEvent(). Метод хорошо описан в Help. При просмотре лога можно отфильтровать события по статусу (Done — информационные сообщения, Passed — успешно пройденные шаги; Warning, Failed — ошибки выполнения теста). Кроме того, записываемыми в лог сообщениями можно управлять из теста с помощью свойства Filter. При значении 0 (по умолчанию), записываются все сообщения; при 1 — Warning и Failed, 2 — failed, 3 — ничего. Причём, не записанные в лог сообщения НЕ влияют на статус теста и статистику.

Существует один хитрый трюк, позволяющий использовать в тексте сообщений лога HTML — см."Undocumented features".

Распознавание объектов в QTP

Вопрос : При воспроизведении записанного теста, QTP не распознаёт объекты. Почему? Что делать?

Ответ:

При записи теста QTP записывает описания объектов интерфейса тестируемого приложения (Application Under Test, AUT), с которыми тест взаимодействует, в Object Repository. Если QTP что-то не распознаёт, с 99.9% вероятности это означает, что свойства распознавания в Object Repоsitory указаны неверно. Это происходит потому, что при записи QTP записывает в Object Repository совершенно определённый набор свойств объекта, одинаковый для каждого отдельного типа объектов. Какие именно свойства QTP записывает для каждого типа объектов определяется настройками Object Idenfication (Tools>Object Identification...).

Следует:

  1. Спомощью Object Spy выяснить, какие именно свойства, из тех что записываются в Object Repository для объекта, меняются от сессии к сессии;
  2. Выяснить, какие свойства не меняются - их можно использовать для распознавания;
  3. Пойти в Object Identification Settings (Tools>Object Identification) и для соответствующего типа объектов правильно настроить свойства распознавания (которые будут прописываться в Object Repository при записи).

Уже записанные скрипты использовать после такой процедуры не рекомендую. Можно, конечно, вручную поменять свойства распознавания для каждого объекта в Object Repository, но это может привести к неприятным последствиям — см. Раздел "Работа с Object Repository"

Вопрос: Как правильно настроить распознавание объектов в QTP с помощью настроек Object Identification?

Ответ:

В настройках Object Identification от обилия опций глаза разбегаются. Однако, всё довольно просто:

Рис.1. Окно Object Identification

Mandatory Properties — свойства, которые QTP прописывает для этого типа объектов в Object Repository ВСЕГДА.

Assistive Properties — свойства, которые QTP прописывает в Object Repository ТОЛЬКО если во время записи объекта в OR в приложении наличествуют более одного объекта, удовлетворяющих Mandatory Properties

Ordinal Identifier — QTP использует, если даже при использовании и Mandatory и Assistive Propertires им удовлетворяет более одного объекта. Ordinal Identifier определённым образом "нумерует" похожие объекты. Делает он это так:

  • Index — по порядку создания в приложении
  • Location — слева направо, сверху вниз
  • Creation Time — только для Browser — по времени создания

Соответственно, в качестве Mandatory свойств надо прописывать такие свойства, которые чаще всего остаются неизменными от версии к версии, но при этом позволяют отличить один объект от другого.

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

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

Настройки QTP по умолчанию не слишком удачны для работы с Win32 GUI приложениями, написанными НЕ на MFC и для динамических страниц Web. Наибольшие проблемы возникают от следующих настроек:

— Standard Windows:

Практически для всех типов объектов в качестве Assistive свойства указано window id. Для приложений, написанных без использования Microsoft Fundation Classes это приводит к тому, что объекты не распознаются при воспроизведении, так как window id меняется от сессии к сессии.

— Web:

Browser — не выставлены Mandatory и Assistive свойства. В качестве Ordinal Identifier используется Creation time. В результате, надёжность воспроизведения зависит от числа открытых браузеров и порядка их создания. Я использую в качестве Mandatory свойства — title.

Настройка Object Identification очень сильно зависит от специфики тестируемого Web-приложения, и какие-то общие рекомендации дать сложно. Рекомендуется с помощью Object Spy выяснить, по каким свойствам легче всего идентифицировать тот или иной тип элемента интерфейса (см. ответ на предыдущий вопрос).

Вопрос: Что такое Smart Identification?

Ответ:

Это такая опция, которую лучше не использовать :) Если серьёзно, то Smart Identification это опция, которая призвана сгладить неумелую настройку пользователем свойств распознавания объектов — с её помощью находятся объекты, которые не удовлетворяют их описанию в Object Repository. Проблема же заключается в том, что эту опцию правильно настроить заметно сложнее чем Object Identification - в результате, её использование у начинающих тестировщиков приводит к тому, что QTP пытается работать не с теми объектами (замечу, что это заметно хуже того случая, когда QTP просто не находит объекта). Опытные же пользователи QTP этой опцией предпочитают не пользоваться — так как умеют настраивать Identification так, что если QTP не находит объекта — значит его нет :)

Интересующихся отсылаю к Help — статья "Smart Identification, configuring"

Вопрос: Можно ли распознавать объекты интерфейса без использования Object Repository?

Ответ:

Можно. Причём, двумя разными способами:

1. C использованием объекта Description:

Пример из Help ("Using Description Objects for Programmatic Descriptions") :

set EditDesc = Description.Create() 
EditDesc("Name").Value = "userName"
EditDesc("Index").Value = "0"
Browser("Welcome: Mercury").Page("Welcome: Mercury").WebEdit(EditDesc).Set "MyName"

2. Явно указывая свойства распознавания:

Синтаксис:

TestObject("PropertyName1:=ProperyValue1", "..." , "PropertyNameX:=ProperyValueX")

Пример из Help ("Entering Programmatic Description Directly into Test Statements"):

Set MyWin = Window("Text:=Myfile.txt - Notepad") 
MyWin.Move 50, 50
MyWin.WinEdit("AttachedText:=Find what:").Set "hello"
MyWin.WinButton("Caption:=Find next").Click

Вопрос: Что делать, если элемент интерфейса тестируемого приложения распознаётся как "WinObject", несмотря на то, что является более специализированным элементом (таким как кнопка, drop-down list, edit box, и т.п.)?

Ответ:

Необходимо настроить распознавание для этого объекта (точнее, для всех объектов с тем же значением свойства native class). Для этого

Вызываем диалог Object Identification: Tools->Object Identification:

Рис.2а: Настройка распознавания объектов нестандартных классов — последовательность действий.

  1. Выбираем Environment->Standard Windows
  2. Жмём на кнопку User Defined...
  3. Вручную заполняем значение поля Class name…
  4. … либо нажав на кнопку с изображением руки указываем нужный нам элемент интерфейса (тогда поле Class name заполнится автоматически)
  5. Выбираем желаемый тип элемента интерфейса
  6. Жмём Add
  7. Жмём OK



    Рис.2б: Настройка распознавания объектов нестандартных классов — результат.
  8. В диалоге Object Identification выбираем добавленный класс и изменяем свойства его распознавания (если нужно)
  9. Жмём OK

Работа с Object Repository

Вопрос: Объекты типа Page/Frame дублируются в Object Repository при записи скрипта. Почему?

Ответ:

Действительно, по умолчанию QTP создаёт новые объект после каждого запроса "POST" на сервер. Чтобы этого не происходило в 6.5:

Tools>Options>Закладка "Web" >Кнопка "Advanced":

Рис.3а: Настройка свойств записи Page/Frame в версии QTP 6.5

Create New Page object for: Установите "Pages with different test object description".

Optimize Page/Frame test object creation - снимите флажок.

 

В QTP 8.2 и 9 эти опции вынесены в отдельный диалог:

Рис.3б: Настройка свойств записи Page/Frame начиная с версии 8.2

Вопрос: В каких случаях QTP создаёт новые объекты в Object Repository (настройка Web settings?)

Ответ:

QTP будет создавать новые объекты в Object Repository если :

  1. Значения свойств объекта не совпадают со свойствами объектов в Object Repository
  2. (ВНИМАНИЕ!) Список свойств объекта, находящегося в Object Repository не совпадает со списком свойств в Object Identification Settings для этого типа объекта. То есть, если Вы изменили описание объекта либо поправили Object Identification Settings, при последующей записи скрипта QTP создаст новый объект.

Поэтому, СНАЧАЛА выставляем Object Identification Settings, потом записываем скрипт. При изменении Object Identification Settings, с большой долей вероятности в репозитории будут создаваться новые объекты.

Вопрос: Чем отличается тип репозитория Shared от per Action?

Ответ (для QTP версий ниже 9.0):

По умолчанию, QTP создает свой Object Repository для каждого Action. Такие репозитории штатными средствами не переносятся из одного Action в другой, не могут быть "слиты" и т.п. Каждый Action может использовать только свой репозиторий.

Кроме "Per-Action" режима работы с OR, существует режим "Shared". Внимание, выбрать режим Object Repository для теста можно только ДО начала его записи. Для этого идём в Test Settings>Resources, и выставляем опцию "Shared".

Рис 4: Выбор типа репозитория для теста в QTP 6.5 — 8.2

Теперь:

  • все Actions используют общий репозиторий
  • общий репозиторий можно использовать из разных тестов
  • общий репозиторий для теста можно поменять.

Ответ (для QTP 9.0):

Начиная с версии 9, в QTP каждый тест может иметь одновременно локальные (для каждого Action'a) и разделяемые (для нескольких тестов) репозитории. Причём, каждый отдельный action может ссылаться одновременно более чем на один shared репозиторий (для каждого action’a репозитории могут быть разные). Как это выглядит? Для того, чтобы проассоциировать каждый action со своим репозиторием надо открыть диалог "Associate Repositories" (Resources>Associate Repositories..):

Рис.5: Окно Associated Repositories в QTP 9.0

Теперь при открытии диалога Object Repository показывается не отдельный репозиторий, а "сумма" проассоциированных с текущим action shared репозториев и локального репозитория Action'a. Конфликты репозиториев разрешаются автоматически — учитывается порядок следования shared репозиториев в списке в диалоге "Action Properties", закладка "Associated Repositories". В окне Object Repository редактировать можно ТОЛЬКО объекты, лежащие в локальном репозитории. Чтобы редактировать shared репозиторий, его необходимо открыть в окне "Object Repositories Manager" (Resources>Object Repository Manager). Причём, не забудьте при открытии убрать опцию "Open as read-only". Object Repository Manager позволяет сливать локальные и shared репозитории, сливать разные shared репозитории с помощью Object Repository Merge Tool, перемещать объекты между репозиториями, и т.п.

Возникает закономерный вопрос: как использовать все эти новые возможности (и зачем они вообще нужны)? Ответ довольно прост — для обеспечения комфортной совместной работы над тестами, использующими один и тот же Shared Object Repository. То есть, пока мы пишем/редактируем наш отдельно взятый тест, мы не меняем объектов в Shared Object Repository. Когда все тесты готовы и отлажены, их Object Respositories сливаются с shared. Вот, собственно и всё (до следующего релиза ;-) ). Ну а новые возможности, такие как использование нескольких репозиториев одновременно, использование различных репозиториев для разных action'ов, экспорт и импорт в XML, я думаю, лишними не будут.

Вопрос: Каким образом свойства распознавания объектов в OR могут поменяться?

Ответ:

Не забывайте при запуске теста в режиме Update Mode снимать галочку "Update test object properties" — иначе все описание всех объектов, с которыми работает тест будут обновлены, причём свойства, отсутствующие в Object Identification Settings для данного типа объектов будут удалены.

Вопрос: Можно ли отказаться от использования Object Repository? Как?

Ответ:

Да, многие тестировщики, работающие с QTP стремятся отказаться от работы с Object Repository. Причин много (правда, многие из них устранены с выходом QTP 9.0). Среди причин отказа от использования Object Repository можно перечислить:

  • проблемы с использованием библиотек совместно с Object Repository. Действительно, в идеале библиотеки функций должны работать вне зависимости от используемого тестом репозитория. Впрочем, проблема скорее идеологическая. В принципе, ничто не мешает разрабатывать библиотеки, имея в виду их работу с определённым репозиторием. Особенно в QTP 9.
  • проблемы правильной настройки Object Identification. Хотя Object Identification настраивается достаточно гибко, тестировщику зачастую хочется самому контролировать, по каким свойствам распознаётся объект.
  • (для версий QTP 6.0-8.0) невозможность совместного использования нескольких Object Repository. В результате приходится использовать один гигантский репозиторий для всех тестов, либо руками создавать объекты (и переименовывать их) в каждом репозитории. А уж если представить себе ситуацию когда с этим репозиторием что-то случится (некоторые версии QTP не слишком дружат с большими репозиториями)... Обратите внимание, что начиная с QTP 9.0 появилась возможность использовать несколько object repositories для одного action'a.
  • (для версий QTP 6.0-8.2) QTP не предоставляет штатных средств для копирования объектов как в пределах одного репозитория, так и между несколькими репозиториями (QTP Plus я в расчёт не беру — он работает не со всеми версиями, и вообще является "кустарным" решением). Внимание, начиная с версии 9.0 появились штатные средства редактирования нескольких репозиторием — Object Repository Manager и Object Repository Merge Tool.

Основной плюс репозитория, в том что это способ повторного использования данных, который позволяет один раз в одном месте изменить описание объекта, который многократно используется тестом. Кроме того, отказавшись от использования репозитория мы автоматически отказываемся от использования записи скриптов. Встаёт вопрос — как отказаться от OR и при этом не лишится этих преимуществ? К сожалению, ни одно решение не позволяет научить QTP записывать тест без использования Object Repository. Другая проблема — повторное использование определений объектов решается с переменным успехом.

Многие пытаются создавать свои альтернативные OR — на XML, в Excel и т.п. Однако, я не вижу больших преимуществ такого решения по сравнению со стандартным Object Repository. Точнее, преимущества есть, но они скрадываются неудобством использования (главным образом — громоздкостью синтаксиса вызова объектов при их использовании либо (при простоте синтаксиса) — отсутствие решения проблем пересечения пространств имён (действительно, неприятно если для всех объектов придется придумывать разные имена вне зависимости от того, к какому объекту верхнего уровня они относятся)).

Мне больше по душе подход, комбинирующий использование объектов Description (для дочерних объектов) с "Helper Functions", возвращающими объекты верхнего уровня, такие как Page, Frame, Window и т.п.:

'== Функция для библиотеки - переводит строку в объект Description

public function TODescriptionFromString(aString)
Dim aProp,aValue
Dim PairsArr,i
Dim aDescription
 set aDescription = description.create 
PairsArr = Split(aString,";")
for i = 0 to UBound(PairsArr)
on error resume next
aprop = Split(PairsArr(i),"=")(0)
aValue = Split(PairsArr(i),"=")(1)
on error goto 0
if aprop<>"" then
aDescription.Item(aprop).value = aValue
end if
next
 set TODescriptionFromString = aDescription
end function

'Oпределяем Description для кнопки

 

   set MyFrame_SearchBtn = TODescriptionFromString("innertext=Search;index=0")
'Helper для Frame'a
public Function GetMyFrame()
set GetMyFrame=Browser("title=My Page").Page("index:=0").Frame("name:=MyFrame")
end function
'Вполне компактная запись получается:
GetMyFrame().WebButton(MyFrame_SearchBtn).Click

Методы Test Object

Вопрос: Как получить доступ к дочерним объектам (если мы не знаем их свойств)?

Ответ:

Для этого есть замечательный метод — ChildObjects. Использовать ChildObject легко, и этот метод достаточно хорошо описан в Help.

Set oDesc = Description.Create() 
oDesc("micclass").Value = "WebList"
Set Lists = Browser("Mercury Interactive").Page("Mercury Interactive").ChildObjects(oDesc)
NumberOfLists = Lists.Count()
For i = 0 To NumberOfLists-1
Lists(i).Select i+1
Next

В Web, метод ChildObjects применим к объектам типа Page и Frame.

Другой способ — использовать Ordinal Identifier в качестве единственного свойства в описании. Тогда пример из Help будет выглядеть примерно так (не слишком изящно, скажем прямо, и, к тому же, заметно медленнее):

Dim listsArr()
Redim listsArr(1000)
i=0
notfound = false
do
if Browser("Mercury Interactive").Page("Mercury Interactive").WebList("index:="&Cstr(i)).Exist(0) then
Set listsArr(i) = Browser("Mercury Interactive").Page("Mercury Interactive").WebList("index:="&Cstr(i))
i=i+1
else
notfound = true
end if
loop until notfound
Redim Preserve listsArr(i-1)
for i = 0 to UBound(listsArr)
listsArr(i).Select i+1
end if

При работе с объектом WebTable используется другой метод — ChildItem (см. Help). К сожалению, как этот, так и другие методы WebTable для работы с ячейками (например, GetCellData) работают чрезвычайно медленно с большими таблицами. В этом случае единственным решением является использование свойства .object таблицы.

Вопрос: Что такое свойство object?

Ответ:

Свойство object есть почти у всех объектов Web (исключением является Browser), объектов VisualBasic, .NET , Java, ActiveX (при установке соответствующих Add-ins). С его помощью можно получить доступ к "родным" (native) свойствам и методам объекта соответствующей среды разработки. Так, свойство object Web-объектов предоставляет доступ к COM-объектам библиотеки MSHTML 4. Те кто знакомы с программированием DHTML страниц, поймут о чём я говорю — получив доступ к объекту элемента DOM мы с ним работаем так же, как если бы мы программировали DHTML cкрипт для Internet Explorer.

Ниже приведён пример работы c полем .object WebTable:

'Эта функция позволяет получить текст ячеек таблицы в виде массива

Public Function tableSaveToArray2D (table,Byref arr)
Dim i,j,rowcount,oTable,colcount,curcc,oRow
Dim fakeArr(0,0)
TableSaveToArray2D = false
If Not isObject(Table) Then
Reporter.ReportEvent micWarning,"tableSaveAsArray2D","Invalid parameter (table)!"
Exit Function
End If
If Not table.exist(10) Then
Reporter.ReportEvent micWarning,"tableSaveToArray2D","Table not found!"
Exit Function
arr = fakeArr
tableSaveToArray2D=false
End If
set oTable = table.Object
rowcount = oTable.Rows.Length

For i = 0 To rowcount -1
set oRow = oTable.Rows(i)
curcc = oRow.cells.length
colcount = Max(curcc,colcount)
Next
Redim Arr(rowcount-1,colcount-1)

For i = 0 to rowcount-1
For j = 0 To colcount-1
On Error Resume Next
Arr(i,j) = Replace(cstr(oTable.rows(i).cells(j).innertext),vbCrLf,"\n")
If Err.description <> "" Then
Arr(i,j) = ""
Err.Clear
end if
On Error goto 0
Next
Next
TableSaveToArray2D = true
End Function

Синхронизация

Вопрос: Тест не дожидается появления/отрисовки объекта, сообщает об ошибке и переходит к выполнению следующих операторов (также с ошибками). Как сделать так, чтобы QTP дожидался появления объектов либо их определённого состояния (например, enabled)?

Ответ:

Этот вопрос хорошо освещён в Help. Cм. "Adding Exist and Wait Statements"," Solving Synchronization Problems", " Modifying Timeout Values".

Вкратце же:

1. Необходимо настраивать установки таймаутов:
Для всех сред:
Object Synchronization Timeout (Test > Settings > Run tab)
Для Web:
Browser Navigation Timeout (Test > Settings > Web tab).

2. Если надо дождаться появления объекта, надо использовать метод .Exist

Синтаксис такой:
.Exist без параметров — ждём Object Syncronization Timeout до появления объекта. Не рекомендуется.

.Exist(timeout) — ждать появления объекта timeout секунд. Возвращает true если удалось дождаться появления объекта, false — если нет. Используем так:

var = TestObject.Exist(timeout)

либо

if not TestObject(timeout) then

end if

К сожалению, запись

TestObject.Exist timeout

не работает, видимо из-за нюансов определения этого метода.

3. Чтобы дождаться нахождения объекта в нужном нам состоянии, используем метод .WaitProperty:

Пример #1

If Browser("index").Page("index").WebEdit("Account").WaitProperty("disabled", 0) 
then
Browser("index").Page("index").WebEdit("Account").Set ("123")
End If
Пример№2
If Browser("index").Page("index").Link("All kind of").WaitProperty("attribute/readyState", "complete", 4000) then 
   Browser("index").Page("index").Link("All kind of").Click 
   End If

 

Свойства Объектов

К сожалению, терминология свойств объектов QTP не слишком прозрачна. Поэтому часто возникает путаница.

Вопрос: Чем отличаются TO Property, RO Property и Run-time object property?

Ответ:

TO Properties — свойства объекта, используемые при его идентификации. Метод GetTOProperty возвращает то значение свойства, которое использовалось при его (объекта) идентификации. Если оно не использовалось, то ничего хорошего не возвращается. Список свойств объекта, которые можно использовать при идентификации указан в Help для каждого класса объектов. TO свойства показываются в Object Spy при выборе опции "Test Object Properties/Methods". Следует обратить внимание на то, что показываются ТОЛЬКО те свойства, которые прописаны в Object Identification, что весьма неудобно.

RO Properties — свойства объектов, в данный момент отображаемых в тестируемом приложении. Их список — тот же, что и у TO Properties. Соответственно, метод GetROProperty возвращает свойства объекта в тестируемом приложении, только если объект этот в данный момент существует (не обязательно отображается).

Run-Time Object properties — поля объекта .object. При тестировании Web есть трюк, позволяющий получить доступ к этим полям при использовании метода GetROProperty и при идентификации. Для этого используется конструкция attrubute/… Например, вот так:

readyState = Browser("index").Page("index").GetROProperty("attribute/readyState")/

Но проще всё же записать так:

readyState = Browser("index").Page("index").object.readyState

Работа с библиотеками и программирование на VBScript

Вопрос: Что такое библиотека функций? Как подключить библиотеку?

Ответ:

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

  • Локальные переменные и функции , определённые в библиотеке не видны в тесте
  • Глобальные переменные и функции, определённые в библиотеке видны во всех Actions
  • Библиотека может содержать код инициализации, который исполняется при её загрузке.

Библиотеки можно подключить на закладке Resources диалога Test Settings (Test>Settings..):

Подключение библиотек

При подключении библиотек обратите внимание на то, что:

  • Можно задать относительный путь;
  • При изменении кода библиотеки, изменения вступают в силу при первом же последующем прогоне теста (кроме случая подключения библиотек из Quality Center/Test Director);
  • Порядок загрузки библиотек имеет значение, но какое именно — пока не выяснено :) - использовать в коде инициализации функции, определённые в других библиотеках, нельзя в любом случае;
  • Библиотеки нельзя подключать программно (из теста).

Вопрос: В чём отличие подключения библиотеки в разделе Test Settings>Resources от использования функции ExecuteFile()

Ответ:

Текст библиотеки, загруженной с использованием ExecuteFile() (см. Help) не доступен при отладке, более того, использование ExecuteFile() приводит к сбою маркера текущей строки при отладке. Кроме этого, ExecuteFile загружает библиотеку в глобальный контекст имён. Поэтому модификаторы доступа, такие как private могут работать некорректно.

Вопрос: Как использовать классы в библиотеках?

Ответ:

Единственная проблема с классами — то что экземпляры классов (то есть, объекты) с помощью оператора New можно создавать только в той же библиотеке, где определён класс (кроме случая загрузки библиотек функцией ExecuteFile()). Поэтому, для создания экземпляра класса из теста или другой библиотеки, необходимо в библиотеке, где определён класс, создать функцию-конструктор. Вот так:

Class MyClass

End class
Function getMyClass()
Set getMyClass = new MyClass
End function

Вопрос: Как использовать функции, определенные в DLL?

Ответ:

Объявить с помощью метода Declare объекта Extern (cм. подробности в Help), после чего процедура либо функция становится методом объекта Extern (пример из Help):

'Declare FindWindow method 
           Extern.Declare micHwnd, "FindWindow", "user32.dll", "FindWindowA", micString, micString 
       'Declare SetWindowText method 
       Extern.Declare micLong, "SetWindowText", "user32.dll", "SetWindowTextA", micHwnd, micString 
       'Get HWND of the Notepad window 
       hwnd = Extern.FindWindow("Notepad", vbNullString) 
       if hwnd = 0 then 
       MsgBox "Notepad window not found" 
       end if 
       'Change the title of the notepad window 
       res = Extern.SetWindowText(hwnd, "kuku")

 

Вопрос: Как работать с объектами COM/ActiveX?

Ответ:

Создавать экземпляры объектов COM/ActiveX можно с помощью функции CreateObject (см. Help по VBScript)

Вопрос: Можно ли редактировать библиотеки?

Ответ:

Начиная с версии QTP 9.0, библиотеки можно редактировать и отлаживать в QTP. Открыть библиотеку можно через меню File либо Resources>Associated Functional Libraries>… (если библиотека ассоциирована с открытым в QTP тестом). Есть одна тонкость, связанная с форматом библиотек — начиная с QTP 9.0, QTP предпочитает хранить библиотеки в формат Unicode (то есть, при некоторых условиях он автоматически преобразует формат библиотеки в Unicode, и сохраняет её в таком виде. Это следует иметь в виду при хранении тестов QTP в системах версионного хранения).

Использование объекта Environment

Вопрос: Зачем нужен объект Environment?

Ответ:

Environment — это коллекция типа Dictionary, содержащая пары ключ — значение, которая видна из всех Actions и из библиотек. Кроме того, Environment содержит многие встроенные значения, относящиеся к текущей сессии исполнения теста, такие как имя пользователя, имя компьютера, имя теста, опции исполнения и т.п. Environment имеет смысл использовать для хранения пользовательских настроек библиотек.

Запуск пакетов тестов и использования QTP Automation Object Model

Вопрос: Как запустить тест/набор тестов из командной строки?

Ответ:

Лучше всего использовать COM-интерфейс QTP - Quick Test Pro Automation. Он подробно описан в Help. Пример из Help:

'**********************************************************************
'Description:
'
'This example opens a test, configures run options and settings,
'runs the test, and then checks the results of the test run.
'
'Assumptions:
'There is no unsaved test currently open in QuickTest.
'For more information, see the example for the Test.SaveAs method.
'When QuickTest opens, it loads the add-ins required for the test.
'For more information, see the example for the Test.GetAssociatedAddins method.
'**********************************************************************

Dim qtApp 'As QuickTest.Application ' Declare the Application object variable 
Dim qtTest 'As QuickTest.Test ' Declare a Test object variable
Dim qtResultsOpt 'As QuickTest.RunResultsOptions ' Declare a Run Results Options object variable
Set qtApp = CreateObject("QuickTest.Application") ' Create the Application object 
qtApp.Launch ' Start QuickTest
qtApp.Visible = True ' Make the QuickTest application visible
' Set QuickTest run options 
qtApp.Options.Run.CaptureForTestResults = "OnError" 
qtApp.Options.Run.RunMode = "Fast"
qtApp.Options.Run.ViewResults = False
qtApp.Open "C:\Tests\Test1", True ' Open the test in read-only mode 
' set run settings for the test 
Set qtTest = qtApp.Test
qtTest.Settings.Run.IterationMode = "rngIterations" ' Run only iterations 2 to 4
qtTest.Settings.Run.StartIteration = 2
qtTest.Settings.Run.EndIteration = 4
qtTest.Settings.Run.OnError = "NextStep" ' Instruct QuickTest to perform next step when error occurs
Set qtResultsOpt = CreateObject("QuickTest.RunResultsOptions") ' Create the Run Results Options object 
qtResultsOpt.ResultsLocation = "C:\Tests\Test1\Res1" ' Set the results location
qtTest.Run qtResultsOpt ' Run the test 
MsgBox qtTest.LastRunResults.Status ' Check the results of the test run 
qtTest.Close ' Close the test
Set qtResultsOpt = Nothing ' Release the Run Results Options object 
Set qtTest = Nothing ' Release the Test object
Set qtApp = Nothing ' Release the Application object

Кроме того, существует утилита Multi Test Manager, поставляемая в составе пакета QTP Plus (входит в QTP, но устанавливается отдельно).

Multi Test Manager

Undocumented features

Вопрос: Можно ли использовать HTML в логах?

Ответ:

Штатными средствами — нельзя. Но если в тексте параметра Description использовать подстроку "&", то описание события показывается в виде HTML. То есть, можно использовать форматирование, вставлять ссылки, делать таблицы, и т.п.

Пример:

Reporter.ReportEvent micDone, "Test HTML reporting", "<DIV style='font-size: 7pt; color: white'>&</DIV><P style='text-align:left'><B>Test</B> <I>HTML</I> Reporting"