3

I'm currently working every day with QuickTest Professional 11, which uses VBScript behind the scenes. Lately, I've started developing some of my own functions to handle common situations. I'm pretty new to VBscript, most of my programming experience is in C and Python.

I'm trying to implement Python's Try/Except in VBScript, mostly to wrap around actions like clicking links or selecting values from dropdown boxes. Here's what I have so far:

Class cls_ErrorHandler
Private bWasError

Private Sub Class_Initialize()
    bWasError = False
End Sub

Private Sub IsErr
    If Err.Number <> 0 Then
        bWasError = True
    Else
        bWasError = False
    End If
            Err.Clear
End Sub

' If the command fails, set bWasError
Public Sub Try(strCommandToTry)
    On Error Resume Next
    Execute(strCommandToTry)
    me.IsErr

    On Error Goto 0
End Sub

Public Sub Except(strCommandInCaseOfError)
    If bWasError Then
        Execute(strCommandInCaseOfError)
    End If
    bWasError = False
End Sub
End Class

I'd like to be able to write things like this:

Set oErrorHandler = New cls_ErrorHandler
oErrorHandler.Try(Stringify(Browser("Browser Name").Page("Page Name").WebCheckBox("Checkbox Name").Set "ON"
oErrorHander.Except(Stringify(Browser("Browser Name").Page("Page Name").WebButton("Save").Click))

As far as I can tell, there really isn't any nice way to pass a function as an argument to another function in VBScript. The best way seems to be to pass a string containing the name of a function, and then feed that string into Execute() or Eval(). Objects in QuickTest Professional tend to have lots of quotation marks, so escaping them all by hand would make the code unreadable.

In C, I'd use something like this:

#define Stringify(obj) #obj

and it would be done... but nothing like that seems to exist in VBScript. Is there any way to implement this? Is there anything in VBScript that takes an object as its input and returns a string representation of that object's name? Would it be possible to write a DLL in C/C# that would provide this kind of functionality?

Patrick Collins
  • 10,306
  • 5
  • 30
  • 69

1 Answers1

3

You can use GetRef to obtain a function/sub pointer, and call the function/sub using that pointer. See online help, it shows an example for an event handler, but you can refer to any global function or sub with GetRef, and use the variable holding the GetRef return value just like an alias for the sub/function.

Be aware, however, that there are cases you won't be able to cover with this:

  • You cannot use a GetRef function pointer if the current calling stack contains a method call that is a function registered to a test object via RegisterUserFunc.

  • You cannot call such a test object method from within a routine call that was adressed via a GetRef function pointer.

Also consider using ExecuteGlobal instead of Execute so the code you pass can set global variables that the ExecuteGlobal caller can access afterwards.

TheBlastOne
  • 4,291
  • 3
  • 38
  • 72
  • 1
    And btw, I don't think you will reach you goal and simulate exception handling for the purposes you outlined. This would catch only runtime errors, and many playback steps simply fail, and, go through QTPs own error handling dialog with "Stop/retry/skip/debug" dialog, but they don't generate VB runtime errors, do they? Headscratching... – TheBlastOne Jun 29 '13 at 06:28
  • QTP's errors seem to be caught by On Error Resume Next, and using Err.Raise seems to drop you into QTP's "stop/try/skip/debug" menu. What I'm looking for is for QTP to be able to fail gracefully if something goes wrong, rather than stopping the whole test and potentially wasting time. As far as I can tell, GetRef takes a string representing the name of the function to be called, which would leave me writing: "Browser(""Browser Name"").Page(""Page Name"").WebButton(""Save"")" which is what I'm trying to avoid by a stringify() function. – Patrick Collins Jun 30 '13 at 15:19
  • I´d switch off interactive dialogs, let the test iteration fail if anything fails, and re-set the AUT's GUI upon (next) iteration start if it is not in its baseline state (test precondition state). Works fine, and keeps everything else as it is designed, and testcases that could be executed get executed, while what failed can be analyzed afterwards. After all, if you have "real" runtime errors, i.e. programming errors in the script, you don´t want to ignore that since continuing with the next testcase would be a waste of time, too. – TheBlastOne Jun 30 '13 at 16:07
  • I suppose that would work. My thinking is just that there are some places where it's likely that a whole branch of the test will fail if something goes wrong -- stuff like "add an entry into the database, check that it came through, edit it, check that the edits came though, delete it." It would be convenient to be able to write tests that say "add an entry into the database. try to edit it, if you can't, quit this whole branch of the test." Something like a stringify() would also let you make map and filter functions. – Patrick Collins Jul 01 '13 at 14:45
  • Ah, I see what you mean -- I tried it my way and QTP still tells me at the end that there was an error in the Except(...) block, which makes this a somewhat useless approach. Oh well. Upvote for you (or I will when I have the requisite 15 reputation, anyway). – Patrick Collins Jul 01 '13 at 19:53
  • +1'd the question since a) you need the respect points lol and b) everybody sometimes gets this idea and attempts it, I guess. So did I, with the conclusions you outlined. Its more of an intrinsic VBS limitation, not a QTP/UFT one. – TheBlastOne Jul 01 '13 at 21:18