Classes, Objects, and QuickTest Pro 9
VBScript is considered to be "object-based", meaning you can use classes, and those classes can have methods and members, but you can't get nearly the kind of re-use and extensibility you could out of a real OOP language. You don't get inheritance, you don't get polymorphism. In short, you get encapsulation, and that's about it. To me that's pretty important, the abilty to wrap up a bunch of common functions and attributes into a single entity called "an object" and throw it around kinda like you would in Java or Ruby. It allows me to create (instantiate) an object in line 10, then count on it being persisted three levels deep and 200 lines later, and never need to look inside the box to find out how it works.
I'll give some code first.
I'm using VBScript classes right now to model our AUT and make the code prettier. For example, if I want to create a user, it looks like this:
-
LoginProfile "ADMIN"
-
Set user = NewUser()
-
user.create(“marcus”, “password”)
-
user.addRole(“Administrator”)
This snippet opens a browser, logs in as an administrator, creates a new User object (basically a variable that holds attributes about a user), then uses that data (if I had supplied any) to actually create user from within the GUI. After the user is created and declared "valid", I call the "addRole()" method off of the same user. The User object knows how to fill out all the form fields. It knows how to add a role through the security interface. How? That's the beauty: I don't have to know. Someone else can develop the library of objects and maintain it, and all I have to know how to do is invoke it.
I know, I know, it's the same with functions. Yes, it is. But here they're all wrapped up together. Consider this:
-
Set userGuest = NewUser()
-
userGuest.create(“guest”, “password”)
-
userGuest.addRole("Guest")
Later, if I want to know the name of that user, I can just ask the object:
-
sName = userGuest.FirstName
Rather than have to code up a function to go and look it up somewhere. It's the persistance of data between states that I'm most interested in. The lack of inheritance and polymorphism is bad, but the most important problems are solved.
Here's the problem: in QTP, you don't just have the limitations of VBScript, you also have some severe limitations built in to (or rather "excluded from") QTP.
The class declaration (in a file called User.vbs) looks like this:
-
Class User
-
Private sUserID
-
Public Function Init ( aOptions )
-
'do some proprietary stuff
-
End Function
-
Public Function create ( sUserName, sPassword )
-
'do some proprietary stuff
-
End Function
-
End Class
-
-
Public Function NewTigerUser ( aOptions )
-
Set NewTigerUser = new User
-
NewTigerUser.Init ( aOptions )
-
End Function
The first limitation:
That last function is there because QTP doesn't have the ability to use classes from external vbs files within the function libraries. You must give the test script access to the above function, which has access to the class, in order for your test script to be able to "see" the class.
The second limitation:
There's a bug in QTP where you can't, no matter what you do, use the debugger to step through class functions. That was almost a showstopper for me when doing this, before I learned just how few of me teammates use the debugger. When I found out I was the only one I decided that for the greater good, OO was a good direction to go in, if for no other reason than to make the code seem more familiar to us non-VBScript types.
So, in short, it's possible for us to get what we need to when we confront OO concepts, but we're severely limited by VBScript as well as Mercury. I'll submit defects on both of these issues, but I'm not sure whether I'd be optimistic about my chances. We seem to be the only ones trying to do this. Let me know if you know different!
Tags: featured, Functions, object-oriented-programming, OOP, QTP 9, QTP-Bugs, QuickTest Pro, Software-Testing, VBScript


September 20th, 2006 at 3:05 pm
I’ve used classes in QTP (8.2 here…still unwilling to take the plunge quite yet), but I’ve rarely seem too much need for them. The encapsulation could be handy, I suppose. Without intellisense to help me know what the members of a particular class are, I am not sure it helps me that much.
I can see some examples that would be great, though. If I have data that I need to read, I can wrap up the code to get it and populate read-only properties off the class to abstract that process. That sort of thing could be very handy in a data-driven process, methinks.
I was curious why you use public members for your properties; you could use use private members and then use Property statements to include validation or verification code which would further abstract the process. Certainly not intended as a critique (I bow always to your team’s knowledge), but more simply to understand your thought. I figure you know something I don’t, basically. :-)
Theo
Reply to Theo Moore
September 20th, 2006 at 4:12 pm
I know nothing that you don’t. I just didn’t want to go into all of that :)
The real classes probably look a lot like you’d imagine, with Property Get()s and Set()s and Class_Initializors, etc., I just thought that stuff was peripheral to the main point.
Along the 9.0 front, I think I’ve discovered another problem with Classes: they seem to cause QTP 9 to hang when they can’t identify an object on a page. It doesn’t happen in every case, but it happens more often than I’d like. When I can isolate it I’ll write it up as a defect.
Reply to Marcus
September 21st, 2006 at 12:30 pm
I just recently installed QTP 9.1. I’m happy to report that you now are able to step into classes while debugging. In version 9.0 and prior, this would cause QTP to hang. It appears to be resolved with QTP 9.1.
Reply to Boyd Patterson
September 22nd, 2006 at 6:30 pm
[...] « Classes, Objects, and QuickTest Pro 9 [...]
Reply to The Software Inquisition » reportStatus() - How we tie Test Level to Assertions
October 2nd, 2006 at 9:35 pm
I have used this method for some time now to enable verification of inputs via an application’s COM interface. I agree with the debugging which would be an advantage. I have not seen any mention of Ver.9.1 features or fixes, but resolution of that point is a step forward.
Reply to Ron Goodwin
December 11th, 2006 at 10:20 am
the article states:
“That last function is there because QTP doesn’t have the ability to use classes from external vbs files within the function libraries. You must give the test script access to the above function, which has access to the class, in order for your test script to be able to ’see’ the class.”
Hum… I must not be understanding your point here, because I can use, in QTP 8.2, a vbScript external lib that contains a simple class, and then access the instantiation of that class in the including QTP script. Here is an example I just ran:
classLib.vbs ——————————
Class message
Private bEnableMsgBox
public property Get EnableMsgBox()
EnableMsgBox=bEnableMsgBox
end property
public property Let EnableMsgBox(bState)
bEnableMsgBox = bState
end property
Private sub Class_Initialize()
bEnableMsgBox = False
end sub
End Class
dim msg
Set msg = New Message
In my QTP script ——————————-
ExecuteFile(”..\classLib.vbs”)
msgBox “msg.EnableMsgBox: ” & msg.EnableMsgBox
msg.EnableMsgBox = True
msgBox “msg.EnableMsgBox: ” & msg.EnableMsgBox
Results ————————————–
The popup msgBox first displays “msg.EnableMsgBox: False”, followed by another msgBox that displays “msg.EnableMsgBox: True”. This clearly indicates that the classLib.vbs message Class, instantiated as the msg Object, is accessible from the including QTP script.
Did I miss your point on this issue?
-Thanks, Terry Horwath
Reply to Terry Horwath
December 13th, 2006 at 5:36 am
I agree with Terry Horwath:
The function ExecuteFile(””) is essential to get it working (QTP9.0).
So there is no first limitation anymore. And that is a good thing.
Reply to Daniel Vermeer
December 13th, 2006 at 9:09 am
Terry,
I had not tried using ExecuteFile to call a library file. Instead, I add library files as test resources.
Your code works as advertised without adding the library file as a resource. Thanks for letting me know about that.
I did find one issue with using ExecuteFile instead of a resource when it comes to debugging code. I can step into functions in files that are included as test resources, but I cannot step into a function if it is in a file included with ExecuteFile. You mentioned using QTP 8.2, so this isn’t an issue for you, but one of my favorite features of QTP 9 is being able to step into function libraries.
Reply to Will
December 13th, 2006 at 10:24 pm
Will,
I have heard others mention problems with debugging/stepping into included lib object code. I think they said (as I am still using 8.2) that this is suppose to be fixed in 9.1. If that is what you are using, then it is disappointing that QTP treats a lib include on the Resource tab differently than one included using ExecuteFile().
Hopefully Merc will fix this as well (and before we upgrade to 9.x!). These proprietary environments are always a challenge. I have also posted several QTPvbScript/WSH articles on http://www.sqaforums.com, on the QTP board, if anyone is interested.
-Terry
Reply to Terry Horwath
April 26th, 2007 at 1:36 pm
In QTP 9.1 you can step into classes in external files in the situation where you instantiate through the wrapper function.
Main file.
Set a = New_A
External file:
Class A
End Class
Public Function New_A()
Set New_A = New A
End Function
If you use ExecuteFile to load the external class file, then you dont have to use the wrapper function, but you cannot step into the class for debugging.
Reply to Cody Marcel
May 1st, 2007 at 4:03 pm
Do anyone of you know how to bind QTP events [[after instantiating Set objQTP = CreateObject(Quicktest.Application object)]] with function in VBS, say CloseQTPcalled. wat i am talking about it that when I call the objQTP.Quit, it should call function CloseQTPcalled??
Reply to ififthelement
July 5th, 2007 at 1:42 am
Dim objqtp ‘As Application
Set objqtp = CreateObject(”QuickTest.Application”)
objqtp.Launch
objqtp.Visible = True
objqtp.Options.DisableVORecognition = False
objqtp.Options.AutoGenerateWith = False
objqtp.Options.WithGenerationLevel = 2
objqtp.new “D:\dummy”,True
objqtp.Application.Quit
“”Not Able to Open the Dummy file of QTP.”"”
“” wanna to open and then run”"”"”"”"”"”"
“what should I do”"”
Reply to Ankur
June 2nd, 2008 at 5:26 am
Thanks for the article. I tried to figure out in what ways classes can be implemented and I wrote an article on it on my blog http://automated-chaos.blogspot.com
Your article (and the comments on it) were a great reference.
Reply to Bas M. Dam