Show Some Class When Using QTP

A lot of testers use QTP as a record-and-playback tool first and then add some logic to start building a framework around whatever their test scripts are. That’s an approach that can work but those same testers often don’t utilize one of the key strengths of QTP, which is it’s object-oriented structure.

Rather than treat it as obvious that using classes is a good idea and without giving a tutorial to object-oriented programming here, I plan to showcase some specifics to keep in mind when using a class-based approach in QTP as well as give a specific example of how this approach can be useful by showing how you can encapsulate your logic for better maintainability.

First, here’s how you can start defining a class.

Visual Basic

1

2

3

4

5

6

7

ClassclsEngine

PrivateSubClass_Initialize

EndSub

PrivateSubClass_Terminate

EndSub

EndClass

Here I have two routines although in this case they are really methods. Adding the Class_Initialize and Class_Terminate methods is not something you have to do. They are essentially constructors and destructors at the class level: Initialize is called when a class object (instance) is created and Terminate is called when a class object is “destroyed.” (Here “destroyed” means that the reference variable for the instance is set to Nothing.) Both methods above are marked as Private and that’s important. The Private modifier marks a method as being available only for code stored within the class being defined. This means that you can’t directly call those methods from outside the class code.

In order to create a method which is callable from outside the class, you have to define it with the Public modifier:

Visual Basic

1

2

3

4

ClassclsEngine

PublicFunctiongrabData()

EndFunction

EndClass

Here grabData is a method that other objects can call.

Inside the class, you can define variables as well. Like methods, variables can also be Private (which means they would only be accessible to members of the class) or Public (which means they can be used by the code from outside the class).

Visual Basic

1

2

3

4

5

6

7

8

ClassclsEngine

PublicsAppFilePath

PrivatesAppName

PublicFunctiongetAppName

getAppName=sAppName

EndFunction

EndClass

In this logic, sAppName cannot be accessed directly. So I have a “getter method” (getAppName) that returns the value. (I trust anyone writing logic like this knows what a getter and setter method is so I’m not really going into that here.)

There are times where you want to protect the class data and control the means by which that data can be accessed. For example, you might want certain data to be accessible from outside the class, but in a mode where it can’t be modified. Another example might be where you want to perform some operations when the data is both read from and written to. (A good example here would be sorting an incoming array, say of stored screen names.) In order to do these things, you can wrap your data elements with a property structure. A property structure is a collection of mini-procedures, specifying what to do when the data is either read from or written to.

In the following example you can see the use of properties encapsulated within Get, Let, and Set structures. Get is used when the data is read, Let when it is written, and Set when it is written with an object reference.

Visual Basic

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

ClassclsEngine

PublicsAppFilePath

PrivatesAppName

PublicPropertyGetAppName

AppName=sAppName

EndProperty

PublicPropertyGetAppFilePath

AppFilePath=sAppFilePath

EndProperty

PublicPropertyLetAppFilePath(sNewFilePath)

sAppFilePath=sNewFilePath

EndProperty

EndClass

The modifier ‘Get’ indicates that the method will be executed when the user reads the property (AppName or AppFilePath). Those methods indicate what value will be returned to the calling method. You can see that AppName only has a Get structure, which means that the AppName can only be read, not modified. The AppFilePath, however, has a Get and Let structure and so it can be read and modified.

Remember that classes are abstract. Just as in any object-oriented language, you do have to create a class object in order to use them. A class object is an instance of the class. You can create many different instance of a class and they all will behave independently of each other:

Visual Basic

1

2

3

4

5

6

7

8

9

10

11

12

ClassclsEngine

PublicsAppFilePath

PrivatesAppName

EndClass

SetexecuteA=NewclsEngine

SetexecuteB=NewclsEngine

executeA.sAppFilePath="c:\Cyborg"

executeB.sAppFilePath="c:\Cryptonomic"

executeA.sAppName="MyApp"

The last statement above will fail because sAppName is a private property.

You can make one class instance point to another, as the last line in the following example shows:

Visual Basic

1

2

3

4

5

6

7

8

9

10

11

12

ClassclsEngine

PublicsAppFilePath

PrivatesAppName

EndClass

SetexecuteA=NewclsEngine

SetexecuteB=NewclsEngine

executeA.sAppFilePath="c:\Cyborg"

executeB.sAppFilePath="c:\Cryptonomic"

SetexecuteA.Parent=executeB

A final note is that when a class refers to itself, you can use the reserved keyword Me. The Me keyword is only allowed from within a class instance, and it is used to refer to that instance “from the outside”. (This is equivalent to ‘this’ in languages like Java and C# or ‘self’ in languages like Ruby or Python.)

Encapsulating Logic for More Maintainability

With that introduction to QTP classes out of the way, I’m going to show you an example of some logic that’s doing a very specific task. Then I’m going to show you a way to make that less complicated. There’s actually a couple of things I’m going to show here.

The use of description objects (instantiated from the Description class).

The ability to get contained objects (via the ChildObjects method).

The ability to determine properties at run-time (via the GetROProperty method).

The use of classes to encapsulate behavior.

I’m really only going to be focusing on the last item in that list. But the other items are things you can think about as you look at the upcoming logic. So, first, here’s the starting logic:

Visual Basic

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

DimoDesc

DimoButton

DimcolObject

SetoDesc=Description.Create

oDesc("micclass").Value="SwfWindow"

SetcolObject=Desktop.ChildObjects(oDesc)

MsgBox colObject.Count

Forx=0TocolObject.Count-1

MsgBox"Name: "&colObject(x).GetROProperty("name")&Chr(13)&_

"Title: "&colObject(x).GetROProperty("title")

Next

SetcolObject=Nothing

SetoButton=Description.Create

oButton("micclass").Value="SwfButton"

SetcolObject=SwfWindow("name:=Home.SignOn").ChildObjects(oButton)

MsgBox colObject.Count

Forx=0TocolObject.Count-1

MsgBox"Name: "&colObject(x).GetROProperty("name")&Chr(13)&_

"Title: "&colObject(x).GetROProperty("title")

Next

SetcolObject=Nothing

Granted that some of this is simply code to print out or clean up and so it’s more supporting code. Still, it’s hard to separate the actual logic of how things are being done from the intent of what I’m doing. In fact, it’s possible to read that and not really have any idea what it’s doing. In fact, that’s a great question: could you even tell what the above logic was doing?

Did you figure it out?

The above code logic is getting a count of certain types of objects on a given screen. But now let’s make all that just a little bit better. First, this logic can be encapsulated within a class. That class can then be instantiated. What that does is make it much easier to make the intent of the calling logic clearer. Here’s the class:

That’s a lot of code, right? How is that getting things better? Well, now you can instantiate that class:

Visual Basic

1

PublicneedTo:SetneedTo=NewclsClassCount

The name “needTo” might seem odd but I’m doing that because it’s going to allow me to convey the intent of what I’m doing. I “need to” do something and so I have a class reference that I refer to with naming that makes this clear. And, as promised, what that does is allow the calling logic to be much simpler:

Visual Basic

1

2

3

4

5

DimBaseObject

SetBaseObject=SwfWindow("name:=Home.SignOn")

MsgBox needTo.GetObjectCount(BaseObject,"SwfButton")

MsgBox needTo.GetVisibleObjectCount(BaseObject,"SwfButton")

Here, of course, I’m just using a MsgBox to print the results but in reality you’d probably have the results of the method calls going to a variable that would then be used in further processing. I think one thing you’ll notice though is that the intent is much clearer in terms of what you are doing and so where and when to use this logic is now hopefully more obvious.

Bottom-line: use classes to your advantage. Don’t just have tools like QTP generate code structures for you and use those. Instead, start building a framework. Classes are a great start on that path to creating frameworks that allow tests and logic to be intent-revealing.

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words.
If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.