Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 17

Descriptive Programming (DP) Concepts – 1

by Anshoo Arora on August 10, 2009


Introduction
Descriptive programming has become the technique of choice for many QTP test developers. We
can talk about its advantages and disadvantages all day, but here, we’ll only discuss the concepts
and come up with our own idea of what it does better, and what it doesn’t :). This is going to be a
very quick refresher before we move on to its everyday application by completing an end-to-end
testcase.
The idea behind descriptive programming is for automation developers to instruct QTP which
properties they would like to use to identify an object, instead of having QTP to choose them
itself. If done correctly, this can help create robustness in scripts, ultimately requiring less
maintenance-time and more development time.
Let’s begin.
But wait, before we really begin, we must understand QTP’s Object Spy. It is an inbuilt tool that
enlists all of the test-object and runtime-object properties. These properties are different for
different types for objects. For example, an image has a property called ‘file name’ whereas a
listbox doesn’t. Instead, a listbox has a special ‘all items’ property whereas the image doesn’t.
This discussion will be limited to the usage test-object properties to identify objects. Below are 2
snapshots of the Object Spy:

Object Spy Icon


Object Spy Window
Now, let’s open www.Google.com and use the object spy to retrieve all properties of the search
box:
Object Spy: WebEdit Properties
Notice the image above. The editbox has a HTML TAG property with its corresponding value
‘INPUT’. This means, the editbox takes some input from the user – which is true because we do
set some value in it! It also has a ‘MAX LENGTH’ property, with a value of ‘2048′. This means,
you can enter a maximum of 2048 characters in it (the best source to see all of the Test-Object
properties of objects is the QTP help itself). Below you will see an editBox which can contain a
maximum of 9 characters:
Test maxLength:

You can really use all these properties to identify this editbox, but, do we really need to use all of
them? No. That is the most important idea behind descriptive programming – we only use what
we need. Below is how we write descriptions for objects:
ObjectClassName("property:=value", "property:=value")

' ofcourse we're not limited to only 2 properties. We can write more:
ObjectClassName("property:=value", "property:=value", "property:=value")
Above, ObjectClassName (in Web applications) can be Browser, Page, Frame, WebEdit, Image
etc. Properties come from the left column the ObjectSpy column whereas values are in the right
column. We can include as many properties as we want, but in reality, we only need to add a few
to uniquely identify the object. Knowing which properties should suffice to uniquely identify can
object will come from experience and practice. Below is a description I created for this editbox
(WebEdit):
'ObjectClassName( "property1:=value1", "property2:=value2" )
WebEdit( "name:=q", "html tag:=INPUT" )
I already mentioned the HTML TAG and its value INPUT above. We’ve also added a new
property/value here: ‘name:=q’. Is this enough to uniquely identify the object? Yes. But is it
enough to make our script work? No, sadly its not.. and that is because, we haven’t yet created
descriptions for its parent objects: Browser & Page. Below are the snapshots of the spied browser
and page objects:
Object Spy: Browser Properties
Object Spy: Page Properties
Browser description:
'ObjectClassName( "property1:=value1" )
Browser( "title:=Google" )
Page description:
Page( "title:=Google" )
Now, we will connect all these descriptions and form a hierarchical tree:
Browser("title:=Google").Page("title:=Google").WebEdit("name:=q","html
tag:=INPUT")
You might wonder why I have omitted the WebTable below the Page and above the WebEdit
object. In practice, we can also skip the Page object to identify the WebEdit. But, why did I skip
the WebTable after all!? When you experiment more with DP, you will discover that some
objects are embedded in many WebTables, and it will become cumbersome if we were to include
all WebTables in the hierarchy to get to the object of interest (thanks to the person who thought
that will be a terrible idea!). Example of the previously mentioned scenario:

Object Spy: Multiple WebTables


To complete the statement above, we will add an event. In QTP, events can be described as
actions on target objects. For example, a WebEdit has a ‘Set’ event. we use the ‘Set’ method of a
WebEdit to set a value:
Browser("title:=Google").Page("title:=Google").WebEdit("name:=q","html
tag:=INPUT").Set "DP"
Set is a QTP event to put in a value in the edit box. Different objects have different events. For
example: an Image has a ‘Click’ event associated with it.
This, we did without using Object Repository. The same concept applies to all objects regardless
of what your environment is. We perform actions on child objects by accessing their object
hierarchies. Let’s complete the above example by searching for our keywords (use the spy again
on the search button):
Browser("title:=Google").Page("title:=Google").WebEdit("name:=q", "html
tag:=INPUT").Set "DP"
Browser("title:=Google").Page("title:=Google").WebButton("name:=Google
Search").Click
This is how the same code will look like if we had recorded this process:
Browser("Google").Page("Google").WebEdit("q").Set "DP is great"
Browser("Google").Page("Google").WebButton("Google Search").Click
These properties are now stored in QTP’s Object Repository (OR). There is another way we can
create object descriptions, which is done by setting a reference:
' Creating Browser description
' "title:=Google"
Set oGoogBrowser = Description.Create
oGoogBrowser( "title" ).value = "Google"

' Creating Page description


' "title:=Google"
Set oGoogPage = Description.Create
oGoogPage( "title" ).Value = "Google"

'* Creating WebEdit description


' "html tag:=INPUt", "name:=q"
Set oGoogWebEdit = Description.Create
oGoogWebEdit( "html tag" ).Value = "INPUT"
oGoogWebEdit( "name" ).Value = "q"
Once we do the above, we can use this descriptions in our script:
Browser(oGoogBrowser).Page(oGoogPage).WebEdit(oGoogWebEdit).Set "DP is great"
The only time I use this technique is to retrive object collections through ChildObjects (we will
discuss this in the coming tutorials).
Let’s do another example. Again, we will use Google, but instead of setting a value, we will
click an object. You can choose any Link on the page; I chose the link ‘Images’:
Object Spy: Google Images Link
'ClassName("property:=value").ClassName("propert1:=value").ClassName("propert
y:=value").Event
Browser("title:=Google").Page("title:=Google").Link("innertext:=Images",
"html tag:=A").Click
This time, instead of ‘Set’ we used ‘Click’. Following is a list of events we perform on Web
objects:
Object Event
Image Click
WebButton Click
WebCheckBox Set
WebEdit Set
WebElement Click
WebList Select
WebRadioGroup Select

Descriptive Programming (DP) Concepts – 2


(Regular Expressions)
by Anshoo Arora on August 10, 2009
A wildcard character can be used to substitute for any other character or characters in a string.1
This means, we can use a wildcard to make our descriptions more generic. For example, if the
property ‘file name’ of an Image is ‘getAllAttributes.JPG’, we can use a wildcard several ways:
' Only using the first 2 words: getAll
Browser( "title:=MyTitle" ).Page( "title:=MyTitle" ).Image( "file
name:=getAll.*" ).Click
' Using 1 word (Attributes) with the extension (JPG)
Browser( "title:=MyTitle" ).Page( "title:=MyTitle" ).Image( "file
name:=.*Attributes.*JPG" ).Click
Let’s put this technique into practice. Let’s use Mercury Tours for this test. Let’s try to identify
the banner image (banner2.gif) having the following text embed: ‘one cool summer ARUBA’.

This image is the property of http://newtours.demoaut.com (HP/Mercury)


Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury
Tours").Image("file name:=banner2.gif").Highlight

Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury


Tours").Image("file name:=banner2.*").Highlight

Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury


Tours").Image("file name:=banner.*").Highlight

Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury


Tours").Image("file name:=ban.*gif").Highlight

Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury


Tours").Image("file name:=ban.*f").Highlight
Ofcourse, there are more ways to identify the banner image, but I’ve only used the above 5.
Similarly, we can use this wildcard character for the Browser and Page objects:
' Without wildcard(s): 0.20 seconds
Browser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury
Tours").Image("file name:=banner2.gif").Click

' With wildcard(s): 0.30 seconds


Browser("title:=Welcome.*").Page("title:=.*Mercury Tours").Image("file
name:=banner2.gif").Highlight

' 0.28 seconds


Browser("title:=Welcome:.*").Page("title:=Welcome.*").Image("file
name:=banner2.*").Highlight

' 0.56 seconds


Browser("title:=.*Mercury Tours").Page("title:=.*: Mercury.*").Image("file
name:=banner.*").Highlight

' 0.61 seconds


Browser("title:=.*Mercury Tour.*").Page("title:=Welcome:.*").Image("file
name:=ban.*gif").Highlight

' 0.51 seconds


Browser("title:=.*: Mercury.*").Page("title:=.*Mercury Tour.*").Image("file
name:=ban.*f").Highlight
You might notice a little drop in performance for some of the above statements. This is quite
obvious though. Using a real world example:
Scenario 1
If you were asked to deliver a letter to John and you had the following piece of information
provided: Building 184, Floor 5, Room 120, Desk 9. You would know that you first have to find
Building A, then take an elevator to the 5th floor, find Room 120, and once you’re inside room
120, John sits on Desk # 9. This is quite straight-forward and ofcourse you’ll be able to quickly
find John.
Scenario 2
In another scenario, if you were asked to deliver a letter to John who is in Building 184 and on
the 5th floor, how would you find John? You would have to go to each room and ask for John,
and make sure it is the correct John before delivering the letter to him. This might take longer.
This is roughly what happens in our scripts. As our descriptions get more and more generic, the
time it takes to identify the object increases. Therefore, even though wildcard characters can
simplify our work, we should be a little careful how we use them.
Regular-Expressions.Info is a good source to learn regular-expressions. We will now do the
exact same test we did about with Banner2.gif, but this time using some more regex style
characters.
' Using the first few characters of the title and the first few characters of
the image
Browser("title:=Welc\w+\D+\w+").Page("title:=Welc\w+\D+\w+").Image("file
name:=ban\w+\d+\.\w+").Highlight

' Using the last few characters of the title with first and last characters
of the image
Browser("title:=\w+\D+\w+ours").Page("title:=\w+\D+\w+ours").Image("file
name:=b\w+2\.gif").Highlight
' Same as above for Browser and Page, but '...' for image
Browser("title:=\w+\D+\w+ours").Page("title:=\w+\D+\w+ours").Image("file
name:=b\w+2\....").Highlight

' Same as above, but replaced 'b' with a '.'


Browser("title:=\w+\D+\w+ours").Page("title:=\w+\D+\w+ours").Image("file
name:=.\w+2\....").Highlight
In the proceeding article we will cover Ordinal Identifiers and also see how to create a simple
test module for a login process.

Descriptive Programming (DP) Concepts – 3


(Ordinal Identifiers)
by Anshoo Arora on August 12, 2009
This is the third article in the Descriptive Programming series, and will outline the concepts of
Ordinal Identifiers used in QTP. We will also create a simple test module (step by step) for a
login process using only Descriptive Programming (DP).

Ordinal Identifiers – What are they?


Let me quote QTP Reference here:
An ordinal identifier assigns a numerical value to a test object that indicates its order or location
relative to other objects with an otherwise identical description (objects that have the same
values for all properties). This ordered value provides a backup mechanism that enables
QuickTest to create a unique description to recognize an object when the defined properties are
not sufficient to do so.
Let’s break the above definition from Mercury/HP into several parts to clarify the concept.
An ordinal identifier assigns a numerical value to a test object
From the quote above, we can conclude that an ordinal identifier is a numerical entity. In other
words, its simply a number that is assigned to a test object.
that indicates its order or location relative to other objects with an otherwise identical description
(objects that have the same values for all properties)
This means, an Ordinal Identifier works quite differently in relation to the properties we learned
in the 1st part of this series. This identifier, or a property if you will, works according to the
order or location of test objects. Objects’ order and location are unique characteristics. For
example, in a coordinate system, generally only a single object exists on a given ‘x,y’ coordinate.
Thus, an ordinal identifier will always be unique. Index defines the order, and location defines
location.
This ordered value provides a backup mechanism that enables QuickTest to create a unique
description to recognize an object when the defined properties are not sufficient to do so.
The quote above is a good way to conclude this concept of Ordinal Identifiers in QTP. Since it is
always unique for an object, it can become extremely useful including these with objects’
mandatory and assisstive properties to prevent falling into object recognition problems. The 3
types of ordinal identifiers are: Location, Index and CreationTime (browser only).
Location Ordinal Identifier
Let’s use an example to understand how the Location Identifier works. Consider the 4 WebEdits
below:
Text Box Text Box
1: 2:

Text Box Text Box


3: 4:

All the edits above have exactly the same properties. This property works vertically, from top to
bottom, and left to right. Thus, ‘Text Box 1‘ will have a location value of 0, ‘Text Box 3‘ will
have 1, ‘Text Box 2‘ will have 2, and ‘Text Box 4‘ will have 3. Note that VBScript is zero based,
so the location property would start at 0. This can be verified by running the following
statements:
'Text Box 1
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t","location:=0").Set "1"

'Text Box 3
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t","location:=1").Set "2"

'Text Box 2
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t","location:=2").Set "3"

'Text Box 4
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t","location:=3").Set "4"
Text Box 1: location=0
Text Box 2: location=2
Text Box 3: location=1
Text Box 4: location=3

Index Ordinal Identifier


Index is quite similar to location, but it works pertaining to appearance of objects in the source
code1. An object appearing prior in the source code will have a smaller Index value as compared
to another object that comes later in the source. Thus, for the same group of edit boxes above:
‘Text Box 1′ will have an index of 0, ‘Text Box 2′ will have 1, ‘Text Box 3′ will have 2 and
‘Text Box 4′ will have 3. Let’s test our statements:
'Text Box 1
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t", "index:=0").Set "1"

'Text Box 2
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t", "index:=1").Set "2"

'Text Box 3
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t", "index:=2").Set "3"

'Text Box 4
Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTes
t", "index:=3").Set "4"
Text Box 1: index=0
Text Box 2: index=1
Text Box 3: index=2
Text Box 4: index=3
That was quite easy, wasn’t it? Now, let’s move on to CreationTime, which is an ordinal
identifier strictly reserved for the browser object.

CreationTime Ordinal Identifier


Again, let’s use the description given by HP/Mercury in QTP’s helpfile:
If there are several open browsers, the one with the lowest CreationTime is the first one that was
opened and the one with the highest CreationTime is the last one that was opened.
That means, the first browser you open will have a creationtime of 0. The second browser will
have a creationtime of 1. The third browser will have a creationtime of 2 and so on.
SystemUtil.Run "iexplore.exe", "http://www.HP.com"
'CreationTime 0
SystemUtil.Run "iexplore.exe", "http://www.AdvancedQTP.com"
'CreationTime 1
SystemUtil.Run "iexplore.exe", "http://www.LinkedIn.com"
'CreationTime 2

Browser( "creationtime:=" ).Highlight 'Highlight HP.com


Browser( "creationtime:=1" ).Highlight 'Highlight AdvancedQTP.com
Browser( "creationtime:=2" ).Highlight 'Highlight LinkedIn.com
When you run the above code in QTP, you will find that the first browser QTP highlights on is
HP.com, the second is AdvancedQTP.com and the third is LinkedIn.com. Even this is quite
simple, isn’t it?
As promised, we must create a simple login process using the concepts we have learned so far in
the next article.

Descriptive Programming (DP) – 4 (Creating


a Test Script)
by Anshoo Arora on August 12, 2009
photo credit: Francisco Javier Martín
This is the last article in our Descriptive Programming series and will cover a simple login
process using 100% DP. I have purposely created the example to be very high-level to make sure
its quit easy to understand. However, if you feel more examples on this concept will help, I’ll be
more than happy to create a Part V of this series with only real-world examples of DP in action.
We will use the HP/Mercury Demo Website for this example.
Following is the process I am going to follow to complete this process. In your application
however, you can use the process that best suits your needs, but for the purposes of this lesson, I
will keep it quite basic:
1. Launch Browser.
2. Check whether the correct browser opened.
3. Ensure the userName, password edits and the Sign-In button exist.
4. Set the userName and password and Click Sign-In.
5. Make sure the browser navigated to the correct page.
Step 1: Launch Browser
'We will use SystemUtil.Run to launch our target browser
SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com/"
Step 2: Checking if the correct browser opened
The 2 new concepts in this step are:
1. Reporter Object: This object is used to send individual reports to the test results. In
other words, when the test ends, you can see the reported events in your Test results.
2. ExitTest: A utility statement available to QTP that enables it to complete exit a Test. In
other words, when this statement executes, the test execution ends.
If Browser( "title:=Welcome: Mercury Tours" ).Exist( 15 ) Then
Reporter.ReportEvent micPass, "Step 1- Launch", "Correct browser was
launched."
Else
Reporter.ReportEvent micFail, "Step 1- Launch", "Browser failed to launch."
ExitTest
End If
Step 3: Ensure the userName, password edits and the Sign-In button exist.
'Notice the use of the wildcard character below
If
Browser("title:=Welcome:.*").Page("title:=Welcome.*").WebEdit("name:=userName"
).Exist(0) Then
'set username
If
Browser("title:=Welcome:.*").Page("title:=Welcome.*").WebEdit("name:=password"
).Exist(0) Then
'set password
If
Browser("title:=Welcome:.*").Page("title:=Welcome.*").Image("name:=login" ).E
xist(0) Then
'click button
Else
'report that Sign-In button was not found
End If
Else
'report that the password edit was not found
End If
Else
'report that the userName edit was not found
End If
Step 4: Set the userName and password and Click Sign-In.
The following will complete the snippet above:
'Notice the use of the wildcard character below
With Browser("title:=Welcome:.*").Page("title:=Welcome.*")
If .WebEdit("name:=userName").Exist(0) Then
.WebEdit("name:=userName").Set "test"
If .WebEdit("name:=password").Exist(0) Then
.WebEdit("name:=password").Set "test"
If .Image("name:=login" ).Exist(0) Then
.Image("name:=login" ).Click
Else
Reporter.ReportEvent micFail, "Sign-In Button Error", "Button not
found."
End If
Else
Reporter.ReportEvent micFail, "Password Edit Error", "EditBox not
found."
End If
Else
Reporter.ReportEvent micFail, "UserName Edit Error", "EditBox not
found."
End If
End With
Step 5: Make sure the browser navigated to the correct page
'Synchronize with a browser
Browser( "title:=.*" ).Sync

'Wait 1 second for browser with "Find a Flight" title to exist


If Browser( "title:=Find a Flight.*" ).Exist( 1 ) Then
Reporter.ReportEvent micPass, "Login", "Login successful"
Else
Reporter.ReportEvent micFail, "Login", "Login failed"
End If
Putting it all together
'We will use SystemUtil.Run to launch our target browser
SystemUtil.Run "iexplore.exe", "http://newtours.demoaut.com/"
If Browser( "title:=Welcome: Mercury Tours" ).Exist( 15 ) Then
Reporter.ReportEvent micPass, "Step 1- Launch", "Correct browser was
launched."
Else
Reporter.ReportEvent micFail, "Step 1- Launch", "Browser failed to launch."
ExitTest
End If

'Notice the use of the wildcard character below


With Browser("title:=Welcome:.*").Page("title:=Welcome.*")
If .WebEdit("name:=userName").Exist(0) Then
.WebEdit("name:=userName").Set "test"
If .WebEdit("name:=password").Exist(0) Then
.WebEdit("name:=password").Set "test"
If .Image("name:=login").Exist(0) Then
.Image("name:=login").Click
Else
Reporter.ReportEvent micFail, "Sign-In Button Error", "Button not
found."
End If
Else
Reporter.ReportEvent micFail, "Password Edit Error", "EditBox not
found."
End If
Else
Reporter.ReportEvent micFail, "UserName Edit Error", "EditBox not
found."
End If
End With

Browser( "title:=.*Mercury.*" ).Sync

If Browser( "title:=Find a Flight.*" ).Exist( 1 ) Then


Reporter.ReportEvent micPass, "Login", "Login successful"
Else
Reporter.ReportEvent micFail, "Login", "Login failed"
End If
If you have any doubt in the content above, please feel free to post a comment about it. I hope
this article helps understand further the principles of Descriptive Programming and using it in
your everyday work.

You might also like