In a previous post, I talked about how I prefer the choice of descriptive programming in terms of my QTP logic for recognizing objects. Descriptive Programming (DP) is a specific approach that QTP makes possible for constructing your recognition strings programmatically. Anyone who has had to modify SilkTest frame files or create XPath-based locators for Selenium will quickly realize that “descriptive programming” is really just a name that QTP has given to what many tools already make possible. In fact, it’s the Object Repository (OR) — the alternative approach in QTP — that tends to be a value-add of QTP beyond other tools, at least for some people.
In any event, my previous post was a little skimpy on specific details so here I’ll look at a specific example of modularizing some test logic using the descriptive approach in QTP.
First, here’s the basis of DP in terms of syntax:
ClassName("property:=value", "property:=value", "property:=value")
Basically you have a class name (indicating a kind of object) and a series of key value pairs, where the key is a property that is exposed by the application and that can be read by QTP for a given object. The above is essentially a description in QTP. You connect a series of such descriptions (corresponding to different objects) and form a hierarchical tree. You can then add an “event” to the tree. To QTP an event is an action you take on an object. The idea is that you perform actions on child objects by accessing their object hierarchies.
With that, here’s a slightly refined basis in terms of syntax:
ClassName("property:=value").ClassName("property:=value").ClassName("property:=value").Event
Basic Example
So here’s a specific and very basic example of how this looks for some objects.
1 2 3 |
SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfEdit("name:=txtUserCode").Set "JNYMAN" SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfEdit("name:=txtPassword").Set "eDrw!83" SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfButton("name:=btnLogin").Click |
That’s a fairly easy way to get the information you need but you’ll note that it’s not very modularized at all.
Variation 1 – Description Objects
You can create object descriptions which allow you to essentially encapsulate all the property information in a “friendly name,” which you can think of as an identifier that hides the details of how that identifier manages to uniquely identify the object in question.
First you’d create some objects:
1 2 3 4 5 |
Set MyApp = Description.Create Set SignOn = Description.Create Set UserCode = Description.Create Set Password = Description.Create Set Login = Description.Create |
Now you can assign property information to these description objects:
1 2 3 4 5 |
MyApp("name").Value = "Home" SignOn("name").Value = "Home.SignOn" UserCode("name").Value = "txtUserCode" Password("name").Value = "txtPassword" Login("name").Value = "btnLogin" |
You can then refer to your objects as such:
1 2 3 |
SwfWindow(MyApp).SwfWindow(SignOn).SwfEdit(UserCode).Set "JNYMAN" SwfWindow(MyApp).SwfWindow(SignOn).SwfEdit(Password).Set "eDrw!83" SwfWindow(MyApp).SwfWindow(SignOn).SwfButton(Login).Click |
Variation 2 – Object Classes
You can also hide many of these details in a class. Then instantiate that class and run methods on it. Here’s an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Class clsSignOn Public Function Using(sUserCode, sPassword) Dim sTitle: sTitle = "Home.SignOn" Using = False With SwfWindow("name:=Home").SwfWindow("name:=" & sTitle) .SwfEdit("name:=txtUserCode").Set sUserCode .SwfEdit("name:=txtPassword").Set sPassword .SwfButton("name:=btnLogin").Click End With If SwfWindow("name:=Home").Exists(5) Then SignOn = True End If End Function End Class |
Then make sure you create a new object of that class:
1 |
Public SignOn : Set SignOn = New clsSignOn |
In that case, with the above structure being created, it means the above commands simply become this:
1 |
SignOn.Using "JNYMAN", "eDrw!83" |
Comparison of Approaches
Here you can consider the different ways the descriptive programming can be used based on how encapsulated it is within other logic.
No Modularity Approach
1 2 3 |
SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfEdit("name:=txtUserCode").Set "JNYMAN" SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfEdit("name:=txtPassword").Set "eDrw!83" SwfWindow("name:=Home").SwfWindow("name:=Home.SignOn").SwfButton("name:=btnLogin").Click |
“Friendly Name” Modularity Approach
1 2 3 |
SwfWindow(MyApp).SwfWindow(SignOn).SwfEdit(UserCode).Set "JNYMAN" SwfWindow(MyApp).SwfWindow(SignOn).SwfEdit(Password).Set "eDrw!83" SwfWindow(MyApp).SwfWindow(SignOn).SwfButton(Login).Click |
Object Class Modularity Approach
1 |
SignOn.Using "JNYMAN", "eDrw!83" |
I like that you can do this kind of thing in QTP with Descriptive Programming because you can start to build up a Test Specification Language (TSL), which is sort of like a Domain Specific Language (DSL) but focused on testing an application. This kind of approach can be done with the Object Repository but I’ve found it to be much more cumbersome and, in fact, it’s simply not what an OR-based approach is built for.
My goal here was to give you a practical example of why I like a descriptive programming approach. Please note, however, that this is an approach that you can take with most tools that allow you to programmatically define selectors and/or locators. The reason I call it out for QTP is simply because many testers are not aware of this since they tend to get indoctrinated into the Object Repository approach fairly quickly.
Thank you. This helped me understand how to use classes concept in QTP.