Relevant Codes (by Anshoo Arora)

A Test Development Resource for HP QuickTest Professional.

QTP: Verify Multiple Object Properties – An Elegant Approach

by Anshoo Arora on August 10, 2009

This article discusses an elegant way of cross-checking expected vs actual properties of objects. The two important components of this technique are:

  1. Modular Classes
  2. DoPropertiesConform Method

Modular Classes
The main concept behind this technique is the usage of Dictionaries. There are 2 types of Dictionaries used in Modular Classes: a Base (Parent) Dictionary and one (or more) Child Dictionaries. All Child Dictionaries are stored in a single Base Dictionary and passed through the class method. This means, if we’re checking object properties in the LogIn page, the Login Class will contain a Base Dictionary and several Child Dictionaries. If we’re checking properties of 2 objects in the LogIn page, there will be 2 Child Dictionaries (1 for each object) and a Base Dictionary. Example:

Class clsLoginPage
 
    ' Private and Public Variables
    ' Other Properties and Methods 

    Public Function Collection
        Dim BaseDictionary      'A Single Parent Dictionary
  
        Dim ChildDictionary_1   '1st Child Dictionary
        Dim ChildDictionary_2   '2nd Child Dictionary
          
        Set BaseDictionary = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_1 = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_2 = CreateObject( "Scripting.Dictionary" )
    End Function
 
End Class

Above, we created 3 dictionaries: 1 Parent and 2 Child. Now, let’s add some properties to the Child Dictionaries:

Class clsLoginPage
 
    ' Private and Public Variables
    ' Other Properties and Methods
 
    Public Function Collection
        Dim BaseDictionary      'A Single Parent Dictionary
  
        Dim ChildDictionary_1   '1st Child Dictionary
        Dim ChildDictionary_2   '2nd Child Dictionary
          
        Set BaseDictionary = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_1 = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_2 = CreateObject( "Scripting.Dictionary" )
 
        With ChildDictionary_1
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        With ChildDictionary_2
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").Image("file name:=logo.gif")
            .Add "html tag", "IMG"
            .Add "width", 50
        End With
    End Function
 
End Class

Above, we added properties to the 2 Child Dictionaries. Please note that, the very first item/key in the dictionary in the Child Dictionaries is the object itself. I have used “Me” denoting that it is the object itself; you can change “Me” to any other descriptive term. However, the first item in the Collection must always be the object. Finally, let’s pass the Child Dictionaries through the method with the help of the Parent Dictionary:

Class clsLoginPage
 
    ' Public and Private Variables
 
    Public Function Collection
        Dim BaseDictionary      'A Single Parent Dictionary
  
        Dim ChildDictionary_1   '1st Child Dictionary (Search WebEdit)
        Dim ChildDictionary_2   '2nd Child Dictionary (SiteLogo Image)
          
        Set BaseDictionary = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_1 = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_2 = CreateObject( "Scripting.Dictionary" )
 
        With ChildDictionary_1
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        With ChildDictionary_2
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").Image("file name:=logo.gif")
            .Add "html tag", "IMG"
            .Add "width", 50
        End With
 
        With BaseDictionary
            .Add "Search", ChildDictionary_1
            .Add "SiteLogo", ChildDictionary_2
        End With
 
        Set Collection = BaseDictionary
    End Function
 
    ' Other Methods and Properties
 
End Class

Above, we passed the Parent dictionary containing both child dictionaries through the method. One last thing here. We must release all objects when we’re done (we will have to declare the variables in the Class scope, instead of method scope):

Class clsLoginPage
 
    Private BaseDictionary      'Parent Dictionary (Class Scope)
    Private ChildDictionary_1   'Child Dictionary 1 (Class Scope)
    Private ChildDictionary_2   'Child Dictionary 2 (Class Scope)
 
    Public Function Collection
        Set BaseDictionary = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_1 = CreateObject( "Scripting.Dictionary" )
        Set ChildDictionary_2 = CreateObject( "Scripting.Dictionary" )
 
        With ChildDictionary_1
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        With ChildDictionary_2
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").Image("file name:=logo.gif")
            .Add "html tag", "IMG"
            .Add "width", 50
        End With
 
        With BaseDictionary
            .Add "Search", ChildDictionary_1
            .Add "SiteLogo", ChildDictionary_2
        End With
 
        Set Collection = BaseDictionary
    End Function
 
    Public Sub Release
        Set BaseDictionary = Nothing
        Set ChildDictionary_1 = Nothing
        Set ChildDictionary_2 = Nothing
    End Sub
 
    ' Private and Public Variables
    ' Other Properties and Methods
 
End Class

Now let’s cover the ‘DoPropertiesConform’ method of this technique.

DoPropertiesConform
This is where all the magic happens (simply keep it in one of your Global libraries and you’re good to go). This method verifies all the properties stored in the Dictionary with the runtime object properties. The final results are reported through Reporter events as HTML tables. The input to this method is the parent dictionary.

'————————————————————————————————————————————— 
' Name: Function DoPropertiesConform
' Purpose: Checks if the expected and actual properties match
' Input:
'    m_htContextBase (Base Collection - this contains several child collections)
' Output: 
'    Boolean
' Date:
' Author: Anshoo Arora
'————————————————————————————————————————————— 
Public Function DoPropertiesConform( ByVal m_htContextBase )
'————————————————————————————————————————————— 
    Dim vKeys, intStatus, i, m_ContextTemp, bResult, keysTemp, oTemp, x, sStatus
 
    DoPropertiesConform = False
 
    vKeys = m_htContextBase.Keys
    intStatus = micPass
 
    For i = 0 to m_htContextBase.Count-1
        ' The below will create temporary references to Collection
        ' In our test, the Collection contains two objects: "Logo" and "UserName"
        Set m_ContextTemp = m_htContextBase.Item(vKeys(i))
        bResult = bResult & "&lt;<table border='1'><tr><td>Status</td><td>Property</td><td>Expected</td><td>Actual</td></tr>"
        keysTemp = m_ContextTemp.Keys
        If m_ContextTemp.Item(keysTemp(0)).Exist(0) Then
            ' Create a temporary reference to the object in the base collection
            ' Key values for these objects must always start with "Me"
            Set oTemp = m_ContextTemp.Item(keysTemp(0))
            For x = 1 to m_ContextTemp.Count - 1
                sStatus = "Pass"
                If Not CStr(oTemp.GetROProperty(keysTemp(x))) = CStr(m_ContextTemp.Item(keysTemp(x))) Then
                    intStatus = micWarning
                    sStatus = "Warning"
                End If
                bResult = bResult & "<tr><td>"&sStatus&"</td><td>"&KeysTemp(x)&"</td><td>"&m_ContextTemp.Item(keysTemp(x))&"</td><td>"&oTemp.GetROProperty(keysTemp(x))&"</td></tr>"
            Next
            Set m_ContextTemp = Nothing
            bResult = bResult & "</table>&gt;" & vbLf
        End If
    Next
    Reporter.ReportEvent intStatus, "DoPropertiesConform", bResult
 
    If intStatus = micPass Then DoPropertiesConform = True
 
    Set m_htContextBase = Nothing
    Set m_ContextTemp = Nothing
End Function

Once we have added all the relevant objects and their properties to the parent dictionary, it just takes the following line of code to run all the verifications:

Call DoPropertiesConform(ParentDictionary)

Download DoPropertiesConform

Examples
In the 2 examples below, we will verify expected and actual properties of the Site Logo and the UserName WebEdit for the Mercury/HP Demo Web Application. Below are the snapshots of the 2 objects verified in the examples:

Site Logo

Site Logo

Mercury Tours: UserName WebEdit

Mercury Tours: UserName WebEdit

Example 1: Case where all properties match (Output = Pass)
Download Example 1

Option Explicit
 
Class clsHomePageObjects
 
    Private m_ContextBase      'Parent
    Private m_ContextLogo      'Child 1
    Private m_ContextUserName  'Child 2
    
    Public Function Collection
        ' Parent Dictionary
        Set m_ContextBase = CreateObject( "Scripting.Dictionary" )
 
        ' Child Dictionaries: m_ContextLogo & m_ContextUserName
        Set m_ContextLogo = CreateObject( "Scripting.Dictionary" )
        Set m_ContextUserName = CreateObject( "Scripting.Dictionary" )
 
        ' Properties of the Object: Site Logo Image
        With m_ContextLogo
            ' Actual Object is the first Item/Key
            .Add "Me", Browser( "title:=Welcome: Mercury Tours" ).Image( "file name:=logo.gif" )
            .Add "alt", "Mercury Tours"
            .Add "file name", "logo.gif"
            .Add "height", "110"
            .Add "name", "Image"
            .Add "width", "100"
        End With
 
        ' Properties of the Object: UserName WebEdit
        With m_ContextUserName
            ' The first Item/Key must always contain the object
            .Add "Me", Browser( "title:=Welcome: Mercury Tours" ).WebEdit( "name:=userName" )
            .Add "disabled", "0"
            .Add "height", "22"
            .Add "kind", "singleline"
            .Add "name", "userName"
            .Add "readonly", "0"
            .Add "rows", "0"
            .Add "type", "text"
            .Add "width", "86"
        End With
 
        ' The Parent Dictionary stores both Child Dictionaries
        With m_ContextBase
            .Add "Logo", m_ContextLogo
            .Add "UserName", m_ContextUserName
        End With
 
        Set Collection = m_ContextBase
    End Function
 
    Public Sub Release
        Set m_ContextBase = Nothing
        Set m_ContextLogo = Nothing
        Set m_ContextUserName = Nothing
    End Sub
 
    ' Private and Public Variables
    ' Other Properties and Methods
 
End Class
 
' Usage:
Dim oNew: Set oNew = New clsHomePageObjects
DoPropertiesConform oNew.Collection
oNew.Release
All Checks Passed

All Checks Passed

In the snapshot above, you will notice that all properties for the site_logo and the userName webEdit passed.

Example 2: Case where some properties match (Output = Fail)
Download Example 2

Option Explicit
 
Class clsHomePageObjects
 
    Private m_ContextBase      'Parent
    Private m_ContextLogo      'Child 1
    Private m_ContextUserName  'Child 2
    
    Public Function Collection
        ' Parent Dictionary
        Set m_ContextBase = CreateObject( "Scripting.Dictionary" )
 
        ' Child Dictionaries: m_ContextLogo & m_ContextUserName
        Set m_ContextLogo = CreateObject( "Scripting.Dictionary" )
        Set m_ContextUserName = CreateObject( "Scripting.Dictionary" )
 
        ' Properties of the Object: Site Logo Image
        With m_ContextLogo
            ' Actual Object is the first Item/Key
            .Add "Me", Browser( "title:=Welcome: Mercury Tours" ).Image( "file name:=logo.gif" )
            .Add "alt", "Mercury Tours"
            .Add "file name", "logo.gif"
            .Add "height", "100" 'Will Fail
            .Add "name", "Image"
            .Add "width", "100"
        End With
 
        ' Properties of the Object: UserName WebEdit
        With m_ContextUserName
            ' The first Item/Key must always contain the object
            .Add "Me", Browser( "title:=Welcome: Mercury Tours" ).WebEdit( "name:=userName" )
            .Add "disabled", "0"
            .Add "height", "21" 'Will Fail
            .Add "kind", "singleline"
            .Add "name", "userName"
            .Add "readonly", "0"
            .Add "rows", "0"
            .Add "type", "text"
            .Add "width", "86"
        End With
 
        ' The Parent Dictionary stores both Child Dictionaries
        With m_ContextBase
            .Add "Logo", m_ContextLogo
            .Add "UserName", m_ContextUserName
        End With
 
        Set Collection = m_ContextBase
    End Function
 
    Public Sub Release
        Set m_ContextBase = Nothing
        Set m_ContextLogo = Nothing
        Set m_ContextUserName = Nothing
    End Sub
 
    ' Private and Public Variables
    ' Other Properties and Methods
 
End Class
 
' Usage:
Dim oNew: Set oNew = New clsHomePageObjects
DoPropertiesConform oNew.Collection
oNew.Release
Some Checks Failed

Some Checks Failed

In the snapshot above, you will notice that there are 2 Warning statuses, one for each object.

I hope you guys find this article useful :)

References

  1. Implementing a GUI Layer of Classes by Meir Bar-Tal (AdvancedQTP, SolmarKN)

If you have any questions, please ask them in the comments section. If your query is confidential, please use the Contact Form to send me an e-mail instead.

{ 28 comments… read them below or add one }

1 Anonymous August 11, 2009 at 9:09 pm

Hai Anshoo,

This is an excellent article.

regards,
testking123

Reply

2 Anshoo Arora August 11, 2009 at 9:10 pm

Thanks! :)

Reply

3 Subhash August 11, 2009 at 9:11 pm

Hi Anshoo

I read the article more than once, understood this and now am trying to create some classes which I can use in my code.

I have a confusion that why we create classes and not just use functions, as later we are calling the functions as methods from a class to serve the purpose.

I might sound novice and my concepts are not clear but if you can help then it will be great.. Do class take more memory then function or like the same question somebody asks “What is advantage of creating a class and not just using functions” then what to do… am searching this on google as well… if you can comment and suggest something then it will be great help.

Reply

4 Anshoo Arora August 11, 2009 at 9:12 pm

I have a confusion that why we create classes and not just use functions, as later we are calling the functions as methods from a class to serve the purpose.

You’re right, we cannot directly call Classes directly. Instead, we call Class members and this is made possible by initializing the class object using the ‘New’ keyword. Example:

Set oNew = New clsMyClass

Set oOld = New clsMyClass

You can use ‘oNew’ and ‘oOld’ above differently, according to your needs, and each instance will behave differently. However, what’s even more important than this concept is the way we can encapsulate a lot of the functionality into a single class, and we reveal only what we want to, through Public Properties, Variables and Methods. Rest, we hide through the use of Private Properties, Variables and Methods. This is a very deep topic, and I would really like to suggest you to find resources on Google and read further, especially about Encapsulation, Polymorphism and Inheritance. However, one must note that VBScript only supports Encapsulation, but understanding the principles of Classes is quite important.

If you look at the classes I have created, I have mentioned that these are modular classes. Thus, if I were to create a separate module for the Login page, everything can be encapsulated into a single working class that checks all the items, logs in the user and verifies if the login was successful.

Using the same example, we can verify the object properties using the methods outlined in this article, verify if all the objects exist, enter username and password, hit submit, wait for the resulting page to appear and report if the Login action was successful or unsuccessful. This entire process can be covered into a single class and it helps binding all of the module methods together.

I hope this helps answer your question. If you’re unclear about any concepts mentioned in this blog, please do let me know.

Thanks – Anshoo

Reply

5 venkat August 16, 2009 at 12:27 pm

Thankyou verymuch

Reply

6 Anshoo Arora August 16, 2009 at 5:31 pm

Thanks :)

Reply

7 Tester October 20, 2009 at 11:07 pm

HI Anshoo Arora,

Iam searching for a tool which can identify the object property and property values of a pirticular webpage.
Can u please let me know if there any such kind of tool to captuure properties according to the QTP properties.
Waiting for your valuable reply
Thanks
Tester

Reply

8 Anshoo Arora October 21, 2009 at 5:23 pm

Sure. There are quite a few actually:

DebugBar
IE Developer’s Toolbar
FireBug

I mostly use DebugBar, but they’re all equally good. You can try them all and see which one you like the most.

Thanks- Anshoo

9 Ranjini November 16, 2009 at 3:12 am

Hi Anshoo,

Can u please explain about the SetCellData method ?In the below code , can we iterate the Group Name with the different datatable values?
JavaWindow(“SPEED”)JavaTable(“Contract Term”).SetCellData “#0″,”Group Name”,”G1″

eg: I have to set the row 1 with the values as G1 and row 2 as G2 and so on … how should i do it ?

Reply

10 Anshoo Arora November 16, 2009 at 12:03 pm

Ranjini,

Unfortunately, I have not worked with Java Applications to give you an accurate answer. You can refer your query to AdvancedQTP’s Java Forum where I’m sure you will find an answer quickly. Also, if I am not wrong, you may just need to run a simple For..Next loop for the number of rows present in the table and use the SetCellData method. The syntax is:

JavaWindow("SPEED").JavaTable("Contract Term").SetCellData RowNumber, ColumnNumber, Data

So, I think you might need to replace #0 with the row number, “Group Name” with the column number.

11 vidyanand.D November 19, 2009 at 2:31 am

Hi,
As per my knowledge wecan get properties of any object with the help of “SPY ONLY” (in QTP), But what is an 3 rd party tools ? & what is the use of these 3 rd party tools, Is an alternate for OBJECT SPY? ,I saw this information on below conversation

Hi Pragya,
I hope you’ve been well.
To answer your question.. all 3 tools that I mentioned in my above post are 3rd party tools. In other words, you can use these even on PCs which do not have QTP installed. Object Spy is dependant on QTP and its not available on PCs where QTP is not installed.
I generally use these tools to better understand the page HTML (without reading the source code) and to find anchors to my target controls

Reply

12 Anshoo Arora November 19, 2009 at 3:16 pm

Hi Vidyanand,

The few 3rd party tools other than QTP that I have described in my post offer much more than what Object Spy does. However, having a good understanding of HTML and CSS helps to use these tools better. Object Spy is a good tool, and I don’t think unless there is a need to understand the page structure without reading the code that you would need to use any of these tools.

I know some advanced users who use DebugBar for finding web anchors in their automation. You can read about identifying those anchors and finding their relationships in this article by Yaron: http://www.advancedqtp.com/knowledge-base/articles/environment-techniques-id15/web-id34/using-web-anchors-to-automate-non-unique-controls/

:)

13 Mahesh Upadhyay December 4, 2009 at 4:24 am

Hi Anshoo,

If i had given 8 child objects for a class then it wont show me the result even it wont show me result if i have 1 child object also, please help me out what is the cause.

Thanks
Mahesh

Reply

14 Anshoo Arora December 4, 2009 at 9:51 am

Hi Mahesh,

Can you please post your code? I am not able to reproduce this issue..

15 Mahesh Upadhyay December 4, 2009 at 4:43 am

Hi Anshoo,

I debug my code i am unable to come into this loop

If m_ContextTemp.Item(keysTemp(0)).Exist(0) Then
       .......................
End IF

Please let me know what process i did wrong
Thanks
Mahesh

Reply

16 Anshoo Arora December 4, 2009 at 9:51 am

Not sure entirely.. You may be creating your dictionary object incorrectly – which is my only guess without looking at the code.

17 Mahesh Upadhyay December 4, 2009 at 4:54 am

Hi Anshoo,

i take a value of
MsgBox(m_htContextBase.Count-1) it shows = 1
but when i tried to take a value of

keysTemp = m_ContextTemp.Keys
MsgBox(keysTemp )

it shows type mismatch so can you please help me out i need to complete it today. hoping for cooperation.

Thanks
Mahesh

Reply

18 Anshoo Arora December 4, 2009 at 9:53 am

It shows “Type Mismatch” because its a collection, and Msgbox “Collection” will not give you a correct result. You will have to loop through the elements in the collection and output each element to know what the collection contains.

For Each oKey in m_htContextBase.Keys
    Print oKey " ---- > " & m_htContextBase.Item(oKey)
Next

19 Mahesh December 4, 2009 at 1:15 pm

Hi Anshoo,

I am using the same code that you provide, just change the title and some properties, i dont have code now but i will show you tommarow, but anyhow if you understand th eproblem so please give me solution.

Thanks
Mahesh

Reply

20 Anshoo Arora December 4, 2009 at 1:44 pm

Hi Mahesh,

I debug my code i am unable to come into this loop

If m_ContextTemp.Item(keysTemp(0)).Exist(0) Then
    …………………..
End IF

I think the only reason why you will not be able to enter that loop is when the object (“Me”) does not exist. If you are executing the same code as I am, please make sure there is only 1 browser open, and that browser is the target browser: http://newtours.demoaut.com

It should work.. I just tested this code on both versions 9.2 and 9.5..

21 Mahesh Upadhyay December 9, 2009 at 5:03 am

Hi Anshoo,

If i wrote a multiple classes for each action and calling the same function “DoPropertiesFunction” so it show me result for 1st action and from second action it shows only Passed even i changed some actual properties value. Can you please help me out, or let me explain how would i able to do it for multiple action. hoping for cooperation.

Thanks
Mahesh

Reply

22 Anshoo Arora December 9, 2009 at 10:36 am

Mahesh, are you keeping the classes in Actions, or in function libraries?

Also, can I see the code that you have there in a .txt file? You can e-mail me the code and I will respond over e-mail or over here, whichever you prefer..

23 Deepak December 10, 2009 at 6:02 am

hi Anshoo,

I need to say that ‘It is a great article.’ I have a question for you.

Why do you pass the value If intStatus micPass Then DoPropertiesConform = False

you are not using it anywhere?

Thanks,
-Deepak

Reply

24 Anshoo Arora December 10, 2009 at 2:21 pm

At the end of the function:

If intStatus <> micPass Then DoPropertiesConform = False

This just means that, if the status of all the checks is not “Passed” then, the result of the Function is going to be “False”. At the beginning of the code, the method starts with:

DoPropertiesConform = True

This means, if there is any descrepency during the checks, the method will return false. I create this to help users even use it in a conditional block:

If DoPropertiesConform(Class.Collection) Then
    'Do Something
Else
    'Do Something Else
End If

25 Pragya October 26, 2009 at 1:34 am

Hey what is this debug bar?? As per your articles, I learned to use object spy to gather the object properties so why this DebugBar?

Reply

26 Anshoo Arora October 26, 2009 at 9:02 am

Hi Pragya,

I hope you’ve been well.

To answer your question.. all 3 tools that I mentioned in my above post are 3rd party tools. In other words, you can use these even on PCs which do not have QTP installed. Object Spy is dependant on QTP and its not available on PCs where QTP is not installed.

I generally use these tools to better understand the page HTML (without reading the source code) and to find anchors to my target controls.

Reply

27 Ranjini November 18, 2009 at 9:21 am

Hi Anshoo,

Thanks for your help. I have referred the Java forum which helped me in resolving my issue. i was able to identify my mistakes when i went to some of the Q&A posted in it .

Reply

28 Anshoo Arora November 18, 2009 at 1:43 pm

Ranjini, I’m glad you have a working solution now :)

Reply

Leave a Comment

{ 3 trackbacks }

Previous post:

Next post: