Descriptive Programming

22
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

Transcript of Descriptive Programming

Page 1: Descriptive Programming

Descriptive Programming (DP) Concepts – 1by Anshoo Arora on August 10, 2009

IntroductionDescriptive 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

Page 2: Descriptive Programming

Object Spy Window

Now, let’s open www.Google.com and use the object spy to retrieve all properties of the search box:

Page 4: Descriptive Programming

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:

Page 6: Descriptive Programming

Object Spy: Page Properties

Browser description:

'ObjectClassName( "property1:=value1" )Browser( "title:=Google" )

Page description:

Page 7: Descriptive Programming

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:

Page 8: Descriptive Programming

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.

Page 9: Descriptive Programming

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.CreateoGoogBrowser( "title" ).value = "Google" ' Creating Page description' "title:=Google"Set oGoogPage = Description.CreateoGoogPage( "title" ).Value = "Google" '* Creating WebEdit description' "html tag:=INPUt", "name:=q"Set oGoogWebEdit = Description.CreateoGoogWebEdit( "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’:

Page 10: Descriptive Programming

Object Spy: Google Images Link

'ClassName("property:=value").ClassName("propert1:=value").ClassName("property:=value").EventBrowser("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

Page 11: Descriptive Programming

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: getAllBrowser( "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 

Page 12: Descriptive Programming

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 secondsBrowser("title:=Welcome: Mercury Tours").Page("title:=Welcome: Mercury Tours").Image("file name:=banner2.gif").Click ' With wildcard(s): 0.30 secondsBrowser("title:=Welcome.*").Page("title:=.*Mercury Tours").Image("file name:=banner2.gif").Highlight  ' 0.28 secondsBrowser("title:=Welcome:.*").Page("title:=Welcome.*").Image("file name:=banner2.*").Highlight  ' 0.56 secondsBrowser("title:=.*Mercury Tours").Page("title:=.*: Mercury.*").Image("file name:=banner.*").Highlight  ' 0.61 secondsBrowser("title:=.*Mercury Tour.*").Page("title:=Welcome:.*").Image("file name:=ban.*gif").Highlight  ' 0.51 secondsBrowser("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 1If 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 2In 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.

Page 13: Descriptive Programming

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 imageBrowser("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 imageBrowser("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 imageBrowser("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.

Page 14: Descriptive Programming

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 1:

Text Box 2:

Text Box 3:

Text Box 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

Page 15: Descriptive Programming

Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest","location:=0").Set "1" 'Text Box 3Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest","location:=1").Set "2" 'Text Box 2Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest","location:=2").Set "3" 'Text Box 4Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest","location:=3").Set "4"Text Box 1: location=0Text Box 2: location=2Text Box 3: location=1Text 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 1Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest", "index:=0").Set "1" 'Text Box 2Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest", "index:=1").Set "2" 'Text Box 3Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest", "index:=2").Set "3" 'Text Box 4Browser("title:=.*Descriptive.*").Page("micclass:=Page").WebEdit("name:=dpTest", "index:=3").Set "4"Text Box 1: index=0Text Box 2: index=1Text Box 3: index=2Text Box 4: index=3

Page 16: Descriptive Programming

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 0SystemUtil.Run "iexplore.exe", "http://www.AdvancedQTP.com" 'CreationTime 1SystemUtil.Run "iexplore.exe", "http://www.LinkedIn.com" 'CreationTime 2

Browser( "creationtime:=" ).Highlight 'Highlight HP.comBrowser( "creationtime:=1" ).Highlight 'Highlight AdvancedQTP.comBrowser( "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

Page 17: Descriptive Programming

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 browserSystemUtil.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." ExitTestEnd If

Step 3: Ensure the userName, password edits and the Sign-In button exist.

'Notice the use of the wildcard character belowIf Browser("title:=Welcome:.*").Page("title:=Welcome.*").WebEdit("name:=userName").Exist(0) Then 'set username If Browser

Page 18: Descriptive Programming

("title:=Welcome:.*").Page("title:=Welcome.*").WebEdit("name:=password").Exist(0) Then 'set password If Browser("title:=Welcome:.*").Page("title:=Welcome.*").Image("name:=login" ).Exist(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 IfElse 'report that the userName edit was not foundEnd 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 belowWith 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 IfEnd With

Step 5: Make sure the browser navigated to the correct page

'Synchronize with a browserBrowser( "title:=.*" ).Sync 'Wait 1 second for browser with "Find a Flight" title to existIf Browser( "title:=Find a Flight.*" ).Exist( 1 ) Then Reporter.ReportEvent micPass, "Login", "Login successful"Else Reporter.ReportEvent micFail, "Login", "Login failed"End If

Page 19: Descriptive Programming

Putting it all together

'We will use SystemUtil.Run to launch our target browserSystemUtil.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." ExitTestEnd If 'Notice the use of the wildcard character belowWith 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 IfEnd 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.