Relevant Codes (by Anshoo Arora)

A Test Development Resource for HP QuickTest Professional.

QTP: Working with Large Object Hierarchies (Siebel Objects)

by Anshoo Arora on September 17, 2009

I received an e-mail from Suni Reddy, who asked me to share with her an easy way of working with Siebel objects – primarily because of their large object hierarchy. I have thought about it several times, but because our work on Siebel goes on a temporary basis, I was never able to come up with something. Until now. This article will describe how you can create a single library with all the parent objects and call those objects on demand.

Normally, if you would like to select an item from a SiebList, you would do something like:

SiebApplication("MyApplication").SiebScreen("MyScreen").SiebView("MyView")_
	.SiebApplet("MyApplet").SiebList("MyList").Select "Open"

The above hierarchy can be greatly simplified – and this article will show a few ways how it can be achieved. Also, the way we’re going to structure our hierarchy, changing one object in a single place will account for an overall change. In other words, instead of changing a single object multiple times (because something changed in the application) we’ll change it only once.

With Statements

This is by far the most common approach used when dealing with large hierarchies, and quite simple too. However, as the parent objects change, we end up creating more and more blocks of such statements. An example of With..End With statement in use:

With SiebApplication("MyApp").SiebScreen("MyScreen1").SiebView("MyView").SiebApplet("MyApplet")
	.SiebList("MyList").Select "Open"
	.SiebButton("MyButton").Click
End With
 
'SibScreen changes from MyScreen1 to MyScreen99: re-write.
With SiebApplication("MyApp").SiebScreen("MyScreen99").SiebView("MyView").SiebApplet("MyApplet")
	'your code
End With

Using Functions to Build Sieb Hierarchy

This technique uses several functions to build a complete hierarchy, but the result is a good one. Moreover, it also simplifies how events are performed on objects. Let’s start by building our first function for the base object (SiebApplication):

'Base Object: SiebApplication
Function oSiebApplication
	Set oSiebApplication = SiebApplication("MyApp")
End function

Let’s create instances for our Child objects:

'oSiebScreen retrieves its parent (oSiebApplication) from the function above
Function oSiebScreen
	Set oSiebScreen = oSiebApplication.SiebScreen("MyScreen")
End Function
 
'oSiebView_ retrieves its parent (oSiebScreen) from the function above
Function oSiebView
	Set oSiebView = oSiebScreen.SiebView("MyView")
End Functions
 
'oSiebApplet retrieves its parent (oSiebView) from the function above
Function oSiebApplet
	Set oSiebApplet = oSiebView.SiebApplet("MyApplet")
End Function

To demonstrate, if we want to set a value in the “lstApplication1″ SiebList, we can simply do the following:

oSiebApplet.SiebList("lstApplication1").Select "Urgent"

I hope the above concept is quite easy to follow, because its used in an OO-methodology below, but with the help of properties.

Using Classes

This is my favorite, and quite similar to what we have above, but, the advantage of using this technique is that we can have multiple classes for multiple Parents, or a single class to group them all together. Assume we have the following hierarchy with an event:

SiebApplication("MyApp").SiebScreen("MyScreen").SiebView("MyView")_
	.SiebApplet("MyApplet").SiebList("lstApplication1").Highlight

First, let’s create a sample class for the Base object(s) that will be common for all classes.

'Demo class for the top-most object (Parent Class)
Class clsSiebApplication
	Public Property Get oSiebApplication
		Set oSiebApplication = SiebApplication("MyApp")
	End Property
End Class

Now, let’s build the child classes, that will use the base class to complete object hierarchies:

'Child Class: Derives its Base Object from clsSiebApplication (Parent Class)
Class clsSiebObjects
	Private oShared
 
	'We will reuse the Base class to retrieve some common objects
	'An instance of the base class will be initialized as the class loads
	Private Sub Class_Initialize		
		Set oShared = new clsSiebApplication
	End Sub
 
	'Terminate the instance while exiting.
	Private Sub Class_Terminate		
		Set oShared = Nothing
	End Sub	
 
	'oSiebScreen Property will retrieve its parent from oSiebApplication
	Public Property Get oSiebScreen
		Set oSiebScreen = oShared.oSiebApplication.SiebScreen("MyScreen")
	End Property
 
	'oSiebView Property will retrieve its parent from oSiebScreen (above)
	Public Property Get oSiebView
		Set oSiebView = oSiebScreen.SiebView("MyView")
	End Property
 
	'oSiebApplet Property will retrieve its parent from oSiebView (above)
	Public Property Get oSiebApplet
		Set oSiebView = oSiebView.SiebApplet("MyApplet")
	End Property
End Class

This can be used in a fashion that makes it very easy for the reader to comprehend with which objects the script is working with. Let’s use the same example we used above with the “lstApplication1″ SiebList:

Dim oSieb
 
'Create an instance of clsSiebObjects
Set oSieb = New clsSiebObjects
 
'Performing an event on the SiebList Object
oSieb.SiebApplet.SiebList("lstApplication1").Highlight

Using an Object Dictionary

This technique is based on Meir’s article, Implementing a GUI Layer with Classes. I would recommend you to read the article to better understand this approach. I have used a high-level approach to this concept, and to better utilize this process, the article must be carefully read. This technique can be used in the following manner to simplify a large object hierarchy:

Class clsSiebObjects
	Private m_htContext
 
	'Loads the Object Dictionary
	Public Function Load
		LoadContext
		Set Load = m_htContext
	End Function
 
	'Represents the Object Context
	Private Function LoadContext
		m_Context = CreateObject("Scripting.Dictionary")
 
		'Loading objects in the dictionary.
		With m_Context
			'SiebApplication
			.Add "SiebApplication", SiebApplication("MyApp")
			'SiebScreen (Parent: SiebApplication)
			.Add "SiebScreen", .Item("SiebApplication").SiebScreen("MyScreen")
			'SiebView (Parent: SiebScreen)
			.Add "SiebView", .Item("SiebScreen").SiebView("MySiebView")
			'SiebApplet (Parent: SiebView)
			.Add "SiebApplet", .Item("SiebView").SiebApplet("MySiebApplet")
		End With
	End Function
 
	'Property Get/Let m_Context
	Private Property Let m_Context(ByVal Val)
		Set m_htContext = Val
	End Property
	Private Property Get m_Context()
		Set m_Context = m_htContext
	End Property
End Class

The snippet below shows usage of the above class to simplify Siebel Hierarchy:

Dim oSieb
 
'Instance of the Class
Set oSieb = New clsSiebObjects
Set oSieb = oSieb.Load
 
oSieb.Item("SiebApplet").SiebPickList("lstApplication1").Select "Open"

Summary

In the examples above, you may notice why only the top 4 objects (Application, Screen, View, Applet) of the hierarchy have been included. This is because, including all the objects will really flood your libraries and make spotting the right object quite a cumbersome task. Thus, by including only the top 4 hierarchies, we can simplify our work on a great scale. If the hierarchy changes, we would simply need to modify the elements at one place, only.

For developers wanting to use Descriptive Programming with Siebel Applications, please note that, you will have to write descriptions for your Parent objects only once. When these descriptions change, updating them in a single place will be the only required maintenance. I am using 100% Descriptive Programming with our Siebel application, and the techniques in this article have really simplified a lot of my work by just taking care of the Parent objects.

I hope Automation Developers using Siebel with QTP find this article useful. Thanks for visiting Relevant Codes.

References

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

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

{ 21 comments… read them below or add one }

1 Pragya September 20, 2009 at 1:46 am

Hey there,

I saw in QTP help that there is a way to close processes in QTP through Process ID. This is the example:

PID = Window("Notepad").GetROProperty("process id")
SystemUtil.CloseProcessById (PID) 

Now my question is: I spied on the Notepad window using Object spy. But there is no such property as Process ID then how GetRoProperty is able to find this particular property when QTP Object spy is not showing this property?

Reply

2 Anshoo Arora September 20, 2009 at 3:42 pm

Hello Pragya,

You raise an excellent question, and honestly, I’m not sure why the folks at HP/Mercury failed to include this property for the Window Class in the Object Spy. Needless to say they must have had a good reason not to, but, I haven’t seen this approach used very much. I have seen usage of WMI to retrieve the process ID, then using .CloseProcessById to close the process:

Dim oWMI, colItem

Set oWMI = GetObject("winmgmts:\\.\root\CIMV2")
Set colItem = oWMI.ExecQuery("SELECT * FROM Win32_Process Where Name ='Notepad.exe'")

For Each oItem In colItem
	MsgBox oItem.processID
Next

If I have your permission, can I include your solution in my article QTP – Closing Multiple Browser Windows? I will cite your comment in the article, giving full credit to you.

Regards,

Anshoo

3 Pragya September 21, 2009 at 7:41 am

Hello Anshoo,

This is not my solution.. Its from QTP help only. And moreover you dont need my permission :) Feel free to add it in your blog.

Can I request you to explain me the WMI code which you have written?

4 Pragya September 20, 2009 at 2:37 am

Hey, I have one more question:

Why is the below mentioned code not running?

Function MySet(obj,x)
Dim y
y=obj.GetROProperty("value")
reporter.ReportEvent micDone, "previous value", y
MySet=obj.Set(x)
End Function

RegisterUserFunc "WebEdit", "Set", "MySet"
Browser("micclass:=Browser").Page("micclass:=Page").WebEdit("micclass:=WebEdit").Set "Pragya"
UnRegisterUserFunc "WebEdit", "Set" 

It gives a general run error in the following line:

y=obj.GetROProperty("value")

I guess it is because the function is declared at the top and it doesnt know what is this obj. So in what sequence i should code it so that it starts working?

Reply

5 Anshoo Arora September 20, 2009 at 3:53 pm

I think this is because you’re trying to override a function that is already a Registered function in QTP. You’re overriding the Set Statement with a definition that reuses Set. I mean to say that, you’re overriding Set but calling it again in your function. I think this is an illegal usage of calling methods.

Meir has written an excellent article on this topic which you will find very interesting. However, because your code stops even before reaching the Set statement, there might be some other issue. I am going to check it tomorrow (since I don’t have QTP on this machine) and get back to you.

Thanks! :)

6 suni September 21, 2009 at 6:45 am

Hi Anshoo,

I am very greatful and thankful to you for ur wonderful post.I appreciate your patience and concern towards all the viewers of ur site, I have just started implementing the above code(using classes my favorite) .little modification in the code End property for oSiebScreen,oSiebView is End sub and last line for set oSiebView is set oSiebApplet i think typo error.The code worked like charm for QTP 8.0 even and only change in the code is the screen,view,applet as the baseclass is constant always.
I am trying the same with multiple screens hope it works ( I doubt how will it pick the correct class, i think for each combination of screen,view,applet we need to define each class )
I dont ask for more .

Cheers
Suni

Reply

7 Anshoo Arora September 21, 2009 at 7:49 pm

Hi Suni,

Thanks for your kind words, and thanks for spotting the error in the code. I have corrected it already! I hope this technique will help you in the long run :)

I am trying the same with multiple screens hope it works

There are several ways you can do this. You can include all the different screens in the same class, or create a new class for them. It depends which approach you find easier to work with, and maintain. When I was writing this article, I did think about it, but did not include working with multiple Screens on purpose. I guess, I thought that the reader should be able to decide which approach they would like to choose, and how they would manipulate it for their environment.

Personally, I would create a separate class and re-use components from the Base Class. That is because it makes the code more readable and if someone else is reading my code, they know what I have done and what they would need to change if there are updates to the application.

8 Pragya September 21, 2009 at 7:45 am

hello Anshoo,

I certainly agree with you that the Article written by Meir is an excellent article but as the name implies, it is Advanced QTP with too technical explanation/code so I am not able to understand it as of now. I am just a beginner in QTP..

I am waiting for your solution Anshoo :) Also your website is great

Reply

9 Anshoo Arora September 21, 2009 at 8:07 pm

Hi Pragya,

I’m not sure if I will be able to simplify it further, or explain it as well as Meir, but let me try my best.

When you register your custom function as a function already registered to QTP, you are overriding all of its methods. When you use your custom MySet, and use Set again within that custom function, QTP uses your Custom Function instead of the inbuild Set function to set a value. In other words:

1. QTP already has a Set Statement which has all the necessary methods to execute it.
2. A user creates another method, overriding the above method
3. Now, once the method in #1 has been overridden by a custom function, the original method loses its functionality to the new (custom) function.

In other words, you are overriding Set and implementing your own version of it. When you do this, Set loses all of its original powers. Also, when it loses its original powers to our custom function, Set fails to work because QTP does not know what Set realls is. Should it Set a value, or should it execute a registered function and do that instead? Hmm. I don’t sound very convincing here.

Demonstration

Function MySet(obj,x)
	Dim y
	y=obj.GetROProperty("value")
	reporter.ReportEvent micDone, "previous value", y

	'This is not allowed because, when QTP tries to Set a value, it refers to
	'your registered function.
	'Your registered function does not define what should be done with the
	'method Set. Why?
	'That is because, you're overriding the inbuild Set method with one of your
	'own - taking away all the actions/events/properties associated with the
	'original set method
	MySet=obj.Set(x)
End Function

10 Anshoo Arora September 23, 2009 at 5:31 pm

This comment is actually a part of an e-mail response to one of the readers of Relevant Codes, but deals with adapting the concepts above with Terminal Emulators instead. The same concept can very well be adapted to a TE environment:

Class clsTeWindow
	Public Property Get oTeWindow
		Set oTeWindow = TeWindow("MyWindow")
	End Property
End Class

Class clsTEParent
    Private oWindow

    Private Sub Class_Initialize
       Set oWindow = New clsTeWindow
       End Sub
    Private Sub Class_Terminate
       Set oWindow = Nothing
    End Sub

    Public Property Screen1
       Set Screen1 = oWindow.oTeWindow.TeScreen("Screen1")
    End Property

    Public Property Screen2
       Set Screen1 = oWindow.oTeWindow.TeScreen("Screen2")
    End Property
End Class

 'Create an instance of Class clsTEParent
Set oTE = New clsTEParent

'For Screen 1:
oTE.Screen1.TeField("FieldName").Set "Something"

'For Screen 2:
oTE.Screen2.TeField("FieldName").Set "Something"

Reply

11 Nikky September 24, 2009 at 10:05 am

Hi Anshoo,

Thanks for your quick response. I tried working on a sample class. I set up the class as above and I have the below sample code in a Test.

Set oTE = New clsTEParent

'For Screen 1:
oTE.Screen1.TeField("FieldName").Set "Something"

I get the following error when I run the code:

class not defined: clsTEParent

Am I missing some step here?

Reply

12 Anshoo Arora September 24, 2009 at 7:53 pm

Hi Nikky,

To make sure the class works, you must keep it and its instantiation within the same library. Therefore:

'This goes inside your function library
Class clsTeParent

End Class

'Also in the function library
Public Function oTe
    Set oTe = New clsTeParent
End Function

In your test:

oTE.Screen1.TeField("FieldName").Set "Something"

I hope this works for you. If you have any questions, or if this still doesn’t work for you, please let me know and we’ll try to make it work.

13 Meenu November 2, 2009 at 11:10 pm

Hi,
I am automating a Seibel application using QTP. Every now and then i am getting following error:
Failed to create object.

I am not creating any object over here and this error occurs on very simple lines of code such .select or .set
Most imp is most of the time this error occur on second run of the code which previously runs fine.
Please Help .

~Meenu

Reply

14 Anshoo Arora November 2, 2009 at 11:26 pm

Hi Meenu,

Can you please share with me the versions of:

1. QTP
2. Siebel Application
3. Siebel Addin
4. IE

Also, in the meantime, you may want to give this a try:

1. Go to: Tools -> Internet Options -> General Tab -> Temporary Files (Settings) -> View Objects
2. Close all IE Windows
3. Delete these 2 files:
Siebel High Interactivity Framework
Siebel Test Automation
4. Restart IE.
5. Login to Siebel -> This will reinstall both objects.

I have had other issues with Siebel, and the above has helped me a few times. At other times, I had to perform a clean install of my system before I stopped seeing such issues. You may want to keep the clean install bit as a last resort though :)

Cheers- Anshoo

15 GK June 24, 2010 at 8:52 pm

Hi Anshoo,

When using classes, i got the same error class not defined: clsclsSiebObjects
Followed the suggestions you made to Nikky about the same issue.

I have attached the library file in the Setting->Resources but the script was not working. So , i have used the ExecuteFile to load the qfl file and the script working well. Is it mandatory to load the qfl file at the beginning of the script to use the classes
Ex:
Call ExecuteFile(“SiebApp.qfl”)
oSieb.oSiebActivityApplet.SiebButton(“uiname:=Query”).Click

Thanks
GK

Reply

16 Anshoo Arora June 28, 2010 at 10:37 am

You will have to create the Class Constructor within the same library to be safe when you are associated libraries. In other words, in your library:

Class clsSiebObjects

End Class

'Constructor
Set oSiebObject = New clsSiebObject

17 GK June 25, 2010 at 12:29 am

Problem solved. Associated the library to the script and it’s working now. Don’t know why it didn’t work before.

Reply

18 Anonymous November 10, 2011 at 7:25 am

Thanks Anshoo!! Very informative article!!

Reply

19 Anshoo Arora September 21, 2009 at 7:53 pm

WMI is quite straight-forward and extremely easy to understand and work with. Below are 3 good resources to learn WMI:

1. MSDN: http://msdn.microsoft.com/en-us/library/aa394582%28VS.85%29.aspx
2. Microsoft Technet: http://technet.microsoft.com/en-us/library/cc180678.aspx
3. Tons of WMI Examples: http://www.cruto.com/resources/vbscript/vbscript-examples/misc/wmi/

I hope this helps :)

PS. I updated the topic Closing Multiple Browser Windows also. Thanks.

Reply

20 Nikky September 25, 2009 at 7:23 am

Hey Anshoo,

Thanks for the tip. My sample class works now! I will implement it my package and will let you know how it goes! Thanks again.

- N

Reply

21 Anshoo Arora October 3, 2009 at 11:27 am

Perfect!! :)

Reply

Leave a Comment

{ 1 trackback }

Previous post:

Next post: