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

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

.
QTP: Реализация GUI слоя при помощи классов
12.05.2009 20:14
Автор: Meir Bar-Tal
Перевод: Сергей Талалаев (SQAdotBY)
Оригинальная статья: Implementing a GUI Layer with Classes

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

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

Эта статья описывает действенную технику, которая используя ООП шаблоны проектирования, дескрипторное программирование (DP) и объект Dictionary позволяет объединить GUI объекты вместе с их бизнес функциями. Статья также включает ценное дополнение: эффективный прием, позволяющий избежать зависания QTP при попытке обращения к несуществующим GUI объектам во время выполнения.

Введение

Основная проблема в автоматизированном тестировании – это как уменьшить издержки по поддержке скриптов. Вопросы вида: “Должны ли мы использовать объектный репозиторий (Object Repository OR) или дескрипторное программирование (Descriptive Programming DP)? Если выбран OR, то должны ли мы использовать общий OR или локальный для каждого Action? Если выбран DP, тогда какой оптимальный вариант его реализации?” достаточно повсеместны и ответы на них могут зависеть как от конкретных особенностей проекта так, во многих случаях, и от людей, вовлеченных в процесс.

В этой статье я проанализирую концепцию Тестовых Объектов (Test Objects) в рамках принципов OO (Object Oriented). Я попытаюсь показать, что реализация объектного репозитория в QTP не соответствует этим принципам, и каково влияние этого факта на разработку автоматизированных тестов с точки зрения эффективности затрат и трудоемкости поддержки. Затем я опишу расширение OR-концепции, которое соответствует принципам OO – GUI слой (GUI Layer). Эта концепция была адаптирована экспертами компании SOLMAR, основываясь на том факте, что возможно максимизировать повторное использование кода (и таким образом улучшить поддерживаемость кода) используя OO подход, согласно которому автоматизируемый проект разбивается на несколько уровней абстракции.

Тестовые Объекты и Run-Time Объекты

Тестовый объект содержит в себе ссылку на run-time объект – объект реального мира, который инициирован в тестовом приложении. Тестовый объект содержит описание объекта, на который он ссылается, в виде набора атрибутов и значений служащих критерием для поиска нужного объекта в ходе тестового прогона. Это описание больше всего похоже на то, что вы себе представляете, идя на встречу с незнакомкой (“Я брюнетка, стройная и высокая, и буду одета в красное платье и туфли”)

Аналогично QTP использует описание для запроса к OS, загружен ли в настоящий момент объект в оперативную память. Если ответ положительный, то OS вернет адрес объекта (ссылку или указатель) и, следовательно, QTP получит доступ к публичным методам и свойствам объекта, в то время как частные методы и свойства остаются скрытыми от просмотра по определению (таким образом QTP никогда не вмешивается в частную область, чего вы бы хотели в отношении брюнетки, если повезет!)

Хотя это описание может быть слишком упрощено, но по существу это такой процесс, который позволяет нам взаимодействовать с GUI (и другими) объектами используя QTP или другое средство автоматизации (Test Partner, Test Complete, Rational Robot, AutoIt и т.д.) Более детальное объяснение различия между Тестовыми Объектами и Run-Time Объектами доступно в статье Yaron Assa "Differences and Connections between Runtime Objects and Test Objects" (2009).

Тестовые Объекты и Объектный Репозиторий

Рассказанное выше естественно заставляет нас думать о тестовых объектах как о данных. Что я имею в виду? Основываясь на описании, построенном из свойств и значений, QTP имеет возможность распознать GUI объект среди всех объектов, загруженных в данный момент в машинную память. Этот процесс подобен тому, как мы получаем необходимую запись из БД согласно условию WHERE в SQL запросе. Разница лишь в том, что в данном случае OS (Windows), а не БД возвращает запись. Кроме того, запись содержит только одно поле – ссылку на реальный run-time объект. Следуя данной мысли, это кажется вполне естественным хранить эти записи - тестовые объекты (Test Objects) – в базе данных, которой собственно Объектный Pепозиторий (Object Repository) и является (если вы обратили внимание на файлы с расширением bdb в QTP тестах, то знайте, что bdb в действительности означает Berkeley Data Base – продукт компании Oracle).

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

Это действительно, правда, что OR, при правильном использовании, предоставляет наилучшую технику, в соответствии с которой нам необходимо сохранить описание каждого GUI объекта всего лишь раз для уменьшения стоимости изменений. Тем не менее, чтобы достичь этого должны быть потрачены большие усилия на правильное управление тестовым проектом, потому что непродуманные запросы и недостаток ресурсов могут привести нарушению целостности этого ценного ресурса (OR). Например, предположим, что два инженера автоматизации работают одновременно с общим репозиторием, но один из них модифицирует скрипт для прошлой версии приложения, а другой – для новой. При условии, что GUI изменения выполняются регулярно от одной версии приложения к другой, не придется долго ждать, пока репозиторий окажется заполненным новыми лишними объектами необходимыми для работы с новой версией приложения. И это еще относительно неплохой результат. Гораздо более худший результат вы получите в случае, если каждый инженер изменяет набор свойств существующих объектов для отражения своих требований, безвозвратно разрушая ROI (возврат инвестиций) проекта автоматизации в целом. Конечно имеются решения и для таких ситуаций, такие как хранение отдельных версий репозитория для соответствующей версии приложения и использование специального ПО по управлению конфигурациями в рамках проекта автоматизации. Но, как говорилось ранее, это требует хорошего управления проектом, что не всегда доступно.

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

Объектно-ориентированный взгляд

Концепция ООП базируется на трех основных принципах – инкапсуляции, наследовании и полиморфизме. Инкапсуляция означает упаковку вместе функциональности и данных, которые сосуществуют вместе и данная упаковка, через которую осуществляются обращения, называется классом. Фактически классы – это представление данных (например, Customer, Product и т.д.) Различие между полнофункциональным классом и обычной структурой данных в том, что класс содержит в себе функции по работе со своими данными - полями. Эти функции обычно называются методами класса. Например, типичный класс для Customer-а включал бы себя следующие поля, которые однозначно определяют покупателя (customerId, firstName, lastName, phoneNo и т.д.) вместе с методами setCustomerId, getCustomerId, которые присваивают и возвращают значения соответствующим полям, также как и getCustomerAge and getCustomerBalance выполняющими расчеты на основе текущих значений полей и возвращающие результат.

Наследование тесно связано с одной из важнейших целей ОО подхода – повторного использование кода. В объектно-ориентированных языках, таких как C++ и Java, повторное использование кода вступает в игру посредством возможности создавать новый класс, который “наследует” поля и методы уже созданного класса (называемого базовым классом) и расширяет их согласно специфическим требованиям, поставленным для нового класса.

Полиморфизм – это еще один мощный принцип, который делает возможным определять несколько версий одной функции (с одним именем, но с различным набором аргументов) для того чтобы прозрачно реагировать на различные ситуации в рамках контекста приложения. Например, у нас есть необходимость производить одну и ту же операцию с различным набором аргументов (float, int) и тогда вместо того, чтобы в одной функции реализовывать набор условных операторов для проверки типов переданных параметров, мы определим несколько функций с одинаковым именем, но с разной сигнатурой (различным набором аргументов). Следовательно, в нашем коде, использующем эти функции, нам не придется использовать приведение типов; мы будем использовать одинаковый интерфейс в обоих случаях, полагаясь на то, что корректный вызов будет осуществлен самой средой выполнения. Тем не менее, в QTP две последние концепции (наследование и полиморфизм) не могут быть реализованы в рамках VB скрипта, который обеспечивает только ограниченную поддержку работы с классами. Тем не менее, позже мы увидим, что это не причина отказываться от использования классов в автоматизации тестирования.

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

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

Автоматизация Тестирования и Разработка ПО

Я был свидетелем одной вещи на протяжении всей моей карьеры – это то, что QA профессионалы всех уровней рассматривают автоматизацию тестирования лишь как особый вид тестовой деятельности. Не удивительно, что не так уж редко можно встретить профессионалов в автоматизации, думающих также о роли автоматизации. Иногда это даже отражается в названии должностей для персонала автоматизации: “авто-тестер” - это одно из абсурдных названий из тех, что я встретил несколько лет назад. Все это отражает непонимание роли Инженера Автоматизации и, как я объясню в дальнейшем, данное мнение действительно не соответствует сущности автоматизации тестирования.

Задача автоматизации тестирования не должна рассматриваться иначе, чем любая другая контекстно-зависимая задача автоматизации. Вообще говоря, компьютерная программа, которая выполняет набор операций вместо человека – реализует автоматизацию. Таким образом, любой блок кода по сути можно рассматривать как автоматическое устройство или робота. Скрипты, которые производят операции над GUI объектами (как тесты в QTP) не отличаются от других частей ПО. Говоря другими словами, проект тестовой автоматизации, несомненно, является специфичным видом проекта по разработке ПО. И как любой программный продукт проект автоматизации также имеет свой собственный документ с функциональными требованиями (Software Requirements Specifications) и дизайн (Software Test Design) документ (либо тест дизайн в одном из промышленных фреймворков, например HP’s Quality Center или Orcanos’ QPack), которыми должен руководствоваться инженер автоматизации при реализации требуемого кода.

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

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

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

  1. В-третьих, GUI-элементы используемые командой разаработки и само поведение приложения могут поставить действительно сложные технологические проблемы касающиеся идентификации объектов на уровне QTP (или другого фреймворка). В большинстве случаев ребуются решения, расширяющие базовые возможности фреймворка особенно в случае использования сторонних и собственных комопонентов.
Следуя описанному выше, я думаю, мы можем заключить, что проект автоматизации определенно должен управляться также как проект разработки. Если это так, почему кто-то должен снова и снова становиться жертвой заблуждения о проекте автоматизации как о тривиальной задаче (методика ”записи-воспроизведения” ничего не напоминает?) в то время как верно обратное? Почему бы тогда не использовать широко применяемый при разработке подход – Объектно Ориентированное Программирование – чтобы достичь наилучших результатов? Далее я опишу методику реализации автоматизированных скриптов, основанную на расширении концепции OR ( GUI слой ) и базирующую на твердых принципах ООП.

Концепция слоев

Я надеюсь, что объяснил достаточно подробно, почему подход с использованием Объектного Репозитория (OR), повсеместно используемый в скриптах, далек от оптимального. Теперь, продолжая начатое обсуждение, позвольте взглянуть на концепцию разработки кода, разделенного на слои или собственно концепцию GUI слоя. Вообще, слои весьма полезны для максимизации повторного использования кода (возвращаясь к предыдущему обсуждению принципов ООП). Я бы определил GUI слой как множество классов, которые объединяют (инкапсулируют) вместе необходимые интерфейсы для манипуляции GUI объектами тестового приложения для выделенной функционально части. Другими словами – это множество классов, обеспечивающих связь между GUI тестового приложения (то есть определенных тестовых объектов) и Бизнес или Прикладным Слоем, о котором мы поговорим позднее. Может быть, было бы более подходящим назвать его Слой GUI-Бизнес Адаптера, но среди экспертов уже устоялся термин GUI Слой, для краткости. Я проиллюстрирую ниже, как такой слой может быть создан и, какие преимущества достигаются при применении данного подхода в рамках тестовой автоматизации.

Реализация GUI Слоя

Инкапсуляция Тестовых Объектов в Классы

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

Class Login

End Class

Class MainWindow

End Class

Class CreateCustomer

End Class

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

'——————————————————————————-
Public Function CreateLogin()
'——————————————————————————-
'Function: CreateLogin
'Creates an instance of the Login class
'
'Remarks:
'
'Arguments:
' N/A
'
'Returns:
' Object - As Login
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

Dim objLogin

Set objLogin = New Login

Set CreateLogin = objLogin
'——————————————————————————-
End Function
'——————————————————————————-

Второй шаг, очевидно, определить список элементов внутри каждого класса. Теперь, так как каждый класс, согласно вышеизложенному – это контейнер других GUI объектов, мы будем использовать Scripting.Dictionary для хранения ссылок на тест-объекты находящиеся на окне, диалоге или странице. (объект Dictionary широко обсуждался в статьях опубликованных в AdvancedQTP’s базе знаний). Таким образом, первый элемент который я представлю здесь, будет общим для всех GUI Layer классов, и я определю его как m_htChildObjects:

Class Login
Private m_htChildObjects 'As Scripting.Dictionary

End Class

Class MainWindow
Private m_htChildObjects 'As Scripting.Dictionary

End Class

и так далее для каждого контекста приложения (ht – префикс для HashTable, чем объект Dictionary на самом деле и является). Частный элемент m_htChildObjects будет доступен через свойство класса ChildObjects. Это свойство определено как:

'——————————————————————————-
'Property: ChildObjects
'Get and Set the m_htChildObjects member field
'
'Remarks:
' R/W
'
'Arguments:
' dic
'
'Returns:
' m_htChildObjects As HashTable
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

Public Property Get ChildObjects()
'——————————————————————————-
Set ChildObjects = m_htChildObjects
'——————————————————————————-
End Property
'——————————————————————————-

'——————————————————————————-
Public Property Let ChildObjects(ByRef dic)
'——————————————————————————-
Set m_htChildObjects = dic
'——————————————————————————-
End Property
'——————————————————————————-

Третий шаг – определение всех объектов внутри каждого контекста. Для этой цели я определю публичный метод Init:

'——————————————————————————-
Public Function Init()
'——————————————————————————-
'Function: Init
'Initializes the context and child objects
'
'Dependencies:
' IsContextLoaded(htContext)
'
'Remarks:
' N/A
'
'Arguments:
' N/A
'
'Returns:
' True/False
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

ChildObjects = CreateObject("Scripting.Dictionary")

With ChildObjects
.Add "Browser", Browser("name:=My App")
.Add "Page", ChildObjects("Browser").Page("title:=My App \- Login")
.Add "Username", ChildObjects("Page").WebEdit("html id:=Username")
.Add "Password", ChildObjects("Page").WebEdit("html id:=Password")
.Add "Submit", ChildObjects("Page").WebButton("outertext:=Submit")
End With

'IsContextLoaded is a function that iterates through the Dictionary and checks if the GUI objects "exist"
Init = IsContextLoaded(ChildObjects)
'——————————————————————————-
End Function
'——————————————————————————-

Часть кода, показанного выше, описывает типичный метод Init для GUI Layer класса страницы логина в Web приложении. Тестовые объекты добавляются, как элементы словаря ChildObjects и их свойства определены посредством Дескрипторного программирования (DP). Читатель может легко провести аналогию с Объектным репозиторием (OR). Благодаря этому встроенному методу мы можем быть уверены, что GUI-объекты всегда определяются в одном месте. В конце кода метода вы можете отметить, что он возвращает результат вызова функции IsContextLoaded которая принимает в качестве аргумента словарь, содержащий ChildObjects.
IsContextLoaded определятся в отдельной общей библиотеке, следующим образом:

'——————————————————————————-
Public Function IsContextLoaded(ByRef htContext)
'——————————————————————————-
'Function: IsContextLoaded
'Checks that the current GUI context is loaded
'
'Iterates through the htContext (HashTable) items and executes the Exist method with 0 (zero) as parameter.
'
'Remarks:
' N/A
'
'Arguments:
' ByRef htContext - As HashTable
'
'Returns:
' True/False
'
'Owner:
' Meir Bar-Tal, SOLMAR Knowledge Networks Ltd.
'
'Date:
' 11-Nov-2008
'
'See Also:
'
'——————————————————————————-

Dim ix, items, keys, strDetails, strAdditionalRemarks

'—————————————————————————
items = htContext.Items
keys = htContext.Keys

For ix = 0 To htContext.Count-1
IsContextLoaded = IsContextLoaded And items(ix).Exist(0)
strDetails = strDetails & vbNewLine & "Object #" & ix+1 & ": '" & keys(ix) & "' was"
If IsContextLoaded Then
intStatus = micPass
strDetails = strDetails & ""
strAdditionalRemarks = ""
Else
intStatus = micWarning
strDetails = strDetails & " not"
strAdditionalRemarks = " Please check the object properties."
End If
strDetails = strDetails & " found." & strAdditionalRemarks
Next
'—————————————————————————

Reporter.ReportEvent intStatus, "IsContextLoaded", strDetails
'——————————————————————————-
End Function
'——————————————————————————-

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

Инкапсуляция бизнес методов в классы

Следующий шаг, после определения дочерних объектов для тестируемого контента – это определение операций, необходимых для выполнения бизнес-сценариев в рамках данного контента. Это легко реализуется через методы класса. Например, класс Login, описанный выше нуждается в следующих методах для начала работы с ним: SetUsername, SetPassword и Submit. Они показаны ниже:

'——————————————————————————-
Public Function SetUsername()
'——————————————————————————-
'Function: SetUsername
'Set the Username field
'
'Dependencies:
' N/A
'
'Remarks:
' N/A
'
'Arguments:
' N/A
'
'Returns:
' N/A
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

ChildObjects("Username").Set GlobalDictionary("Username")
'——————————————————————————-
End Function
'——————————————————————————-

'——————————————————————————-
Public Function SetPassword()
'——————————————————————————-
'Function: SetPassword
'Set the Password field
'
'Dependencies:
' N/A
'
'Remarks:
' N/A
'
'Arguments:
' N/A
'
'Returns:
' N/A
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

ChildObjects("Password").Set GlobalDictionary("Password")
'——————————————————————————-
End Function
'——————————————————————————-

'——————————————————————————-
Public Function Submit()
'——————————————————————————-
'Function: Submit
'Presses the Submit button
'
'Dependencies:
' N/A
'
'Remarks:
' N/A
'
'Arguments:
' N/A
'
'Returns:
' N/A
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

ChildObjects("Submit").Click

'TODO: Verify data submission performed successfully
'——————————————————————————-

End Function
'——————————————————————————-

Отметим использование GlobalDictionary для получения требуемых значений для функций (username, password) и использование свойства ChildObjects для получения через тестовый объект ссылки на выполняемый объект.

Следующим шагом будет перемещение на Бизнес Слой (Business Layer), который реализует бизнес сценарий, построенный на базе GUI Слоя (GUI Layer). Например, для того чтобы выполнить логин в систему на основе вышеописанного примера мы реализуем следующую функцию:

'——————————————————————————-
Public Function do_login()
'——————————————————————————-
'Function: do_login
'Implements the business logic of the do_login Action.
'
'Remarks:
'
'Arguments:
' None
'
'Returns:
' Status
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

Dim intStatus, objLogin

Set objLogin = CreateLogin()
If objLogin.Init() Then
objLogin.SetUsername()
objLogin.SetPassword()
objLogin.Submit()

'If login succeeds
intStatus = micPass
Else
intStatus = micFail
End If

do_login = intStatus
'——————————————————————————-
End Function
'——————————————————————————-

Отметим использование класса Login описанного выше и его функции Init как меру предосторожности для уверенности, что необходимый контент загружен и не завис, как обсуждалось ранее. Как вы можете видеть, код вышеописанной функции достаточно просто для понимания, и не перегружен ссылками на OR объекты, источники данных как при обычной реализации. Если изменения на GUI затронут объекты в данном контенте – все изменения будут сконцентрированы только в данном пакете, как те что касаются собственно свойств объектов так и механизмов работы с дочерними объектами. Еще одно преимущество данной методики – это стандартизация. Разрабатывая код по данной схеме, мы достигаем высокой степени унификации кода написанного разными разработчиками и таким образом улучшаем управляемость тестового проекта.

Более продвинутая альтернатива последнему примеру – это упаковка таких бизнес-функций, используя Command Wrapper шаблон проектирования, как это описано в моей статье Function Pointers in VB Script (revised). Например:

'VB Script Document
Option Explicit

'——————————————————————————-
Class do_login
'——————————————————————————-
'Class: do_login
'Encapsulates the do_login Action.
'
'Remarks:
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-
'——————————————————————————-
'Methods
'——————————————————————————-
'——————————————————————————-

Public Default Function Run()
'——————————————————————————-
'Function: Run
'Implements the business logic of the do_login Action.
'
'Remarks:
'
'Arguments:
' None
'
'Returns:
' Status
'
'Owner:
' John Doe
'
'Date:
' dd-MMM-yyyy
'
'——————————————————————————-

Dim intStatus

Set objLogin = CreateLogin()
If objLogin.Init() Then
objLogin.SetUsername()
objLogin.SetPassword()
objLogin.Submit()

'If login succeeds
intStatus = micPass
Else
intStatus = micFail
End If

Run = intStatus
'——————————————————————————-
End Function
'——————————————————————————-
'——————————————————————————-

End Class
'——————————————————————————-

Адаптация данной методики делает возможным реализацию продвинутых универсальных контроллеров (generic controller), которые загружают свои сценарии из внешних источников данных, таких как XML файл. Такие управляющие структуры были разработаны мной и моими партнерами в SOLMAR Knowledge Networks как часть нашего универсального фреймворка - Object Oriented comprehensive automation framework - My System.

Выводы


В данной статье рассматривался альтернативный подход реализации тестов при автоматизации, основанный на объектно-ориентированной методологии. Я показал, что автоматизацию не следует рассматривать иначе, чем разработку программ. Более того, я постарался отразить, что логически следуя данной мысли, мы приходим к заключению, что проект автоматизации должен рассматриваться как программный проект в идеале, и предложил расширение концепции Объектного Репозитория (OR) (которая показала несоответствие OR методологии ООП) для инкапсуляции интерфейсов GUI объектов: GUI Слой.
В статье также приводился практический пример реализации такого слоя и его вызов, используя Бизнес-Слой, и разъяснены в деталях преимущества такого подхода для достижения максимального эффекта от вложенных инвестиций (ROI) в проекте автоматизации относительно поддерживаемости, читаемости, масштабируемости, расширяемости и тестируемости. Следующие статьи расширят данную тему и покажут читателям, как получить выигрыш от реализации в фреймворке других шаблонов проектирования, помимо изложенных в рамках этой статьи.

Обсудить в форуме