April 26, 2009

How to use classes in QTP revisited

Classes in QTP are a bit tricky if you want to use them for the first time. You have to know and understand the principle that a class got local scope for the QTP Function Library (.qfl file) it is in, and that if you want to use it in another library, you’ll have to create a constructor (I have shown this before, but I’ll do it again):


' Constructor:
Public Function [new CustomClass]()
     Set [new CustomClass] = new cls_CustomClass
End Function

' Class definition:
Class cls_CustomClass
     Private Sub Class_Initialize()
         Print "Custom Class: I am created!"
     End Sub
End Class

' using the object in another library:
Dim myClass
Set myClass = [new CustomClass]

This seems like a drawback, but it creates a great possibility. Normally, it is not possible to pass initialisation parameters into a new class, because Class_Initialize does not accept parameters. But using the constructor function, we can!

Option Explicit

' Make a private variable that we can pass into the class
Private PARAMETER_ARRAY

' Create a function that returns the requested class. Accepts
' a parameter array. Note: Do not use paramArray, it is reserved!
Public Function [new customClass](ByVal parameterArray)

     PARAMETER_ARRAY = parameterArray

     ' Return a clsCustomClass object
     Set [new CustomClass] = new cls_CustomClass

End Function

' Create the custom class. Classes are always declared Private in QTP
Class cls_CustomClass

     ' The sub Class_Initialize is used to initialize the object with the
     ' parameters passed into the constructor
     Private Sub Class_Initialize()
         ' Do something with the parameters
         Print join(PARAMETER_ARRAY, vbNewLine)
     End Sub

End Class

' Test code
Dim myClass
Set myClass = [new customClass](array("first parameter", "second parameter", "etc."))

Notice what we just did: We created a Private variable, that can only be used by CustomClass classes. So with the use of Private variables with local scope to the library where you put the class in, you create a static variable for the class!
A static variable in this context is a variable that keeps its value and can be used over multiple objects of the same class:

' Declaring the static variables
Private INSTANCE_COUNTER : INSTANCE_COUNTER = 0

' Constructor:
Public Function [new CustomClass]()
     Set [new CustomClass] = new cls_CustomClass
End Function

' Class definition:
Class cls_CustomClass
     Private Sub Class_Initialize()
         Print "I am created and I have " & INSTANCE_COUNTER & " sister(s)."
         INSTANCE_COUNTER = INSTANCE_COUNTER + 1
     End Sub

     Private Sub Class_Terminate()
         INSTANCE_COUNTER = INSTANCE_COUNTER – 1
     End Sub
End Class

' using the object in another library:
Dim a, b, c
Set a = [new CustomClass]
Set b = [new CustomClass]
Set c = [new CustomClass]

Results in:
I am created and I have 0 sister(s).
I am created and I have 1 sister(s).
I am created and I have 2 sister(s).

By using the static variable as a reference for the object itself, we can create a singleton object. A singleton is an object whereof only one instance at a time can exist. In object oriented languages, singletons are normally used for large objects, or objects that will go bad if multiple instances exists like deadlocks or instability.

Option explicit

Private SINGLETON : Set SINGLETON = Nothing

Public function [new Singleton]()
     If SINGLETON Is Nothing Then
         set SINGLETON = new cls_Singleton
     End If

     Set [new Singleton] = SINGLETON
End Function

Class cls_Singleton

     Private Sub Class_Initialize
         Print "I am unique!"
     End Sub

End Class

Dim st1, st2, st3
Set st1 = [new Singleton]
Set st2 = [new Singleton]
Set st3 = [new Singleton]

Results in only one:
I am unique!

There is a drawback: Once a singleton object is created this way, it is not possible to destroy it without the use of some code violating the object oriented principle.

8 comments:

Unknown said...

Thanks Bas for this article. I had implemented a class and a function wrapper but I would like to know how I make the the object (class I wrote) exposes the properties and methods by using the dot notation. When I use the object on my QTP scripts, I need to know in advance which method or property to invoque, because when I type the dot nothing happens. In other words, I would like to have the same functionality that when I use objects from the Object Repository.

Roberto

Bas M. Dam said...

Well, as you may have noticed, the IDE of QTP has its shortcomings once you are in the Expert view:
- no autorecognition of subs and functions that are not in the same module
- no declaration check
- no function viewer (I'm working on good old version 9.1)
- and, as you noticed, no autocomplete for home brew classes

Maybe you should try Test Design Studio by Patterson Consulting. It solves all shortcomings of the IDE of QTP and very more. And, it is not very expensive in comparison to QTP itself. One drawback: You cannot run scripts with TDS, only design them (hence the name).

RLD said...

Ohhh, Thank You. I've been trying to get this to work for awhile.

But, in your first example, I had to add a "new" to get it to work. Does this make sense:

Set [new CustomClass] = new cls_CustomClass

Bas M. Dam said...

RLD, you are totally right. This slipped through, thanks for clearing it out!

Albert Gareev said...

Hi Bas,

Great solution.
I came to the similar one to implement VBscript function overloading and parameter defaulting. I used Dictionary object in my solution.
You're more than welcome to check it out.
http://automationbeyond.wordpress.com/2009/06/25/overload-vbscript/

Anonymous said...

hello... hapi blogging... have a nice day! just visiting here....

Unknown said...

Hi,

I have a question here. I have declared a class in a function library. When I try to create an object from any action (say action1), QTP displays an error that "Class is not defined". Can you please tell me if it is feasible to work in the way mentioned above or Do I need to follow a different process altogether?
Thanks in Advance.

Regards,
Leela

Anonymous said...

Hi Leela,

Any class declaration is private in QTP. You can use a code like "Set objMyClass = new MyClass" only within the function library where it is declared.

To workaround that you need to define a class constructor function returning an instance to the class.

Example.

Public Function CreateMyClass
Set CreateMyClass = new MyClass
End Function

The function has to be defined in the same library as your class.

- Albert Gareev