QTP: Verify Multiple Object Properties – An Elegant Approach

by Anshoo Arora ON August 10, 2009 · Posted In All, QTP · 31 comments

Article revised on 04/04/2012

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 a Dictionary object to hold property-value pairs. There are 2 types of Dictionary objects 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. In practice, if we’re checking properties for the LogIn page, the Login Class will contain a Base Dictionary and several Child Dictionaries. Example:

Class LoginModule
 
    Public Function Collection
        Dim BaseDictionary 'A Single Parent Dictionary
  
        Dim Search   '1st Child Dictionary
        Dim SiteLogo '2nd Child Dictionary
          
        Set BaseDictionary = CreateObject("Scripting.Dictionary")
        Set Search = CreateObject("Scripting.Dictionary")
        Set SiteLogo = 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 LoginModule
 
    Public Function Collection
        Dim BaseDictionary 'A Single Parent Dictionary
  
        Dim Search   '1st Child Dictionary
        Dim SiteLogo '2nd Child Dictionary
          
        Set BaseDictionary = CreateObject("Scripting.Dictionary")
        Set Search = CreateObject("Scripting.Dictionary")
        Set SiteLogo = CreateObject("Scripting.Dictionary")
 
        With Search
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        With SiteLogo
            .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 LoginModule
 
    Public Function Collection
        Dim BaseDictionary  'A Single Parent Dictionary
  
        Dim Search    '1st Child Dictionary (Search WebEdit)
        Dim SiteLogo  '2nd Child Dictionary (SiteLogo Image)
          
        Set BaseDictionary = CreateObject("Scripting.Dictionary")
        Set Search = CreateObject("Scripting.Dictionary")
        Set SiteLogo = CreateObject("Scripting.Dictionary")
 
        With Search
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        With SiteLogo
            .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", Search
            .Add "SiteLogo", SiteLogo
        End With
 
        Set Collection = BaseDictionary
    End Function
 
End Class

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

Class LoginModule
 
    Private BaseDictionary 'Parent Dictionary (Class Scope)
    Private Search         'Child Dictionary 1 (Class Scope)
    Private SiteLogo       'Child Dictionary 2 (Class Scope)
 
 
    Public Function Collection
        Set BaseDictionary = CreateObject("Scripting.Dictionary")
        Set Search = CreateObject("Scripting.Dictionary")
        Set SiteLogo = CreateObject("Scripting.Dictionary")
 
        'Child Dictionary #1
        With Search
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").WebEdit("name:=q")
            .Add "html tag", "INPUT"
            .Add "width", 100
        End With
 
        'Child Dictionary #2
        With SiteLogo
            .Add "Me", Browser("title:=Google").Page("micclass:=Page").Image("file name:=logo.gif")
            .Add "html tag", "IMG"
            .Add "width", 50
        End With
 
        'Add the Child Dictionary objects to Base
        With BaseDictionary
            .Add "Search", Search
            .Add "SiteLogo", SiteLogo
        End With
 
        Set Collection = BaseDictionary
    End Function
 
    Public Sub Dispose
        BaseDictionary.RemoveAll : Set BaseDictionary = Nothing
        Search.RemoveAll : Set Search = Nothing
        SiteLogo.RemoveAll : Set SiteLogo = Nothing
    End Sub
 
End Class

The Modular class is ready and holds a Base collection with several Child collections.

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 BaseDictionary 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.

'Arg:
'    DictBase - Base Collection - this contains several child collections
'Returns:
'    Boolean (True if all properties in the collection match)

Public Function DoPropertiesConform(ByVal DictBase)
    Dim vKeys, intStatus, i, m_ContextTemp, bResult, keysTemp, oTemp, x, sStatus, css, StepInfo
 
    DoPropertiesConform = False
 
    vKeys = DictBase.Keys
    intStatus = micPass
 
    For i = 0 to DictBase.Count-1
        ' The below will create temporary references to Collection
        ' In our test, the Collection contains two objects: "Logo" and "UserName"
        Set m_ContextTemp = DictBase.Item(vKeys(i))
        bResult = bResult & "<table id='custom' border='1'><tr><th>" & _
                    "Status</th><th>Property</th><th>Expected</th><th>Actual</th></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 = "<span style='color:green;'>Pass</span>"
 
                If Not CStr(oTemp.GetROProperty(keysTemp(x))) = CStr(m_ContextTemp.Item(keysTemp(x))) Then
                    intStatus = micWarning
                    sStatus = "<span style='color:orange;'>Warning</span>"
                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>" & vbLf
        End If
    Next
 
    css = "<style>#custom {font-family: Calibri, Arial;font-size: 12px;background: #fff;" & _
            "margin: 10px;width: 480px;border-collapse: collapse;text-align: left;}" & _
            "#custom th{font-size: 14px;font-weight: normal;color: #039;padding: 10px 8px;" & _
            "border-bottom: 2px solid #6678b1;}#custom td{border-bottom: 1px solid #ccc;color:" & _
            "#669;padding: 6px 8px;}#custom tbody tr:hover td{color: #009;}</style><body>"
 
    Set StepInfo = CreateObject("Scripting.Dictionary")
    StepInfo("ViewType") = "Sell.Explorer.2"
    StepInfo("DllIconIndex") = 206
    StepInfo("DllIconSelIndex") = StepInfo("DllIconIndex")
    StepInfo("DllPAth") = Environment.Value("ProductDir") & "\bin\ContextManager.dll"
    StepInfo("Status") = intStatus
    StepInfo("NodeName") = "DoPropertiesConform"
    StepInfo("StepHtmlInfo") = "<html>" & css & bResult & "</body></html>"
 
    Reporter.LogEvent "User", StepInfo, Reporter.GetContext
 
    If intStatus = micPass Then DoPropertiesConform = True
 
    Set DictBase = 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)

Example

In the example 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 LogoMercury Tours: UserName WebEdit

Class HomePage
 
    Private m_ContextBase      'Parent
    Private m_ContextLogo      'Child 1
    Private m_ContextUserName  'Child 2
    
    Public Function Collection
        ' Parent Dictionary (Base)
        Set m_ContextBase = CreateObject("Scripting.Dictionary")
 
        ' Child Dictionary objects
        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 Dispose
        Set m_ContextBase = Nothing
        Set m_ContextLogo = Nothing
        Set m_ContextUserName = Nothing
    End Sub
 
End Class
' Usage:
Dim NewHomePage
Set NewHomePage = New HomePage
 
DoPropertiesConform NewHomePage.Collection
NewHomePage.Dispose
Result:

Result

I hope you guys find this article useful :)

Subscribe to Relevant Codes (by Anshoo Arora)

Hello! We're always posting interesting articles on Relevant Codes. Why not subscribe so you don't miss out?

Leave a Comment

{ 28 comments… read them below or add one }

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

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

Reply

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

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..

Reply

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

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..

Reply

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

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

Reply

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

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.

Reply

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

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..

Reply

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

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/

:)

Reply

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

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.

Reply

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

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

Reply

Anshoo Arora August 16, 2009 at 5:31 pm

Thanks :)

Reply

venkat August 16, 2009 at 12:27 pm

Thankyou verymuch

Reply

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

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

Anshoo Arora August 11, 2009 at 9:10 pm

Thanks! :)

Reply

Anonymous August 11, 2009 at 9:09 pm

Hai Anshoo,

This is an excellent article.

regards,
testking123

Reply

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

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

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

Anshoo Arora November 18, 2009 at 1:43 pm

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

Reply

{ 3 trackbacks }

Previous post:

Next post: