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:

Visual Basic:
  1. LoginProfile "ADMIN"
  2. Set user = NewUser()
  3. user.create(“marcus”, “password”)
  4. 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:

Visual Basic:
  1. Set userGuest = NewUser()
  2. userGuest.create(“guest”, “password”)
  3. userGuest.addRole("Guest")

Later, if I want to know the name of that user, I can just ask the object:

Visual Basic:
  1. 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:

Visual Basic:
  1. Class User
  2.     Private sUserID
  3.     Public Function Init ( aOptions )
  4.         'do some proprietary stuff
  5.     End Function
  6.     Public Function create ( sUserName, sPassword )
  7.         'do some proprietary stuff
  8.     End Function
  9. End Class
  10.  
  11. Public Function NewTigerUser ( aOptions )
  12.     Set NewTigerUser = new User
  13.     NewTigerUser.Init ( aOptions )
  14. 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: , , , , , , , ,

13 Comments for “Classes, Objects, and QuickTest Pro 9”

  1. Theo Moore Says:

    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

  2. Marcus Says:

    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

  3. Boyd Patterson Says:

    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

  4. The Software Inquisition » reportStatus() - How we tie Test Level to Assertions Says:

    [...] « Classes, Objects, and QuickTest Pro 9 [...]

    Reply to The Software Inquisition » reportStatus() - How we tie Test Level to Assertions

  5. Ron Goodwin Says:

    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

  6. Terry Horwath Says:

    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

  7. Daniel Vermeer Says:

    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

  8. Will Says:

    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

  9. Terry Horwath Says:

    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

  10. Cody Marcel Says:

    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

  11. ififthelement Says:

    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

  12. Ankur Says:

    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

  13. Bas M. Dam Says:

    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

Leave a Reply