VBScript’s error handling techniques have been quite limited to On Error statements, and even though they satisfy our needs to some extent, the lack of incorporating dynamic behavior with them has been a much bigger issue. Lee Harvey here shows how Classes can be extended to create simple Try-Catch-Finally statements with just a bit more work. I like this technique, and have been using it for the past few days with success. We know that this is not the best solution that is possible with a scripting language (JS does a lot better!), but its a start and a terrific workaround (thanks Lee!).
Creating Try-Catch-Finally Statements in VBScript
If you have already read Lee’s article, you can skip this part. Otherwise, a simple implementation is shown below:
- As soon as the class executes, it enters Class_Initialize – Try statement
- It encounters an error – Err.Raise 1002
- As soon as it encounters an error, the Try statement (Class_Initialize) immediately ends execution
- Because we’re releasing the Class reference using
Set NewTryCatchFinally = Nothingright after initializing it, the Class enters Class_Terminate - Class_Terminate calls the Catch subroutine
- When Catch runs in its entirety, Class_Terminate executes
On Error Resume Next Class TryCatchFinally Private Sub Class_Initialize 'Try Print "Entering Try.." & vbNewLine Err.Raise 1002 'Raise a Syntax Error MsgBox "This line will not execute" End Sub Private Sub Catch 'Catch If Err.Number = 0 Then Exit Sub Print "Entering Catch.." Print "Error caught: " & Err.Description & vbNewLine Err.Clear End Sub Private Sub Class_Terminate : Catch 'Finally Print "Exiting.." End Sub End Class Set NewTryCatchFinally = New TryCatchFinally : Set NewTryCatchFinally = Nothing
The output of executing the above code should be the following:
Try Catch Finally Implementation in VBScript
We can see from the result that as soon as the Class executes, it enters Class_Initialize. When it encounters an error, it enters into Class_Terminate which contains (and executes) the Catch method. A simple yet such an elegant solution!
Utility Class & Error Handler
In this article, I will try to implement the technique with QTP’s GUI objects. To begin, let’s create a simple Login class with the following methods:
CheckPageCheckImageLogin
The Login Class outputs the result through the Result property:
A simple Login Class
On Error Resume Next Class Login Public Property Get Result Result = CheckPage And CheckImage And Login End Property Private Function CheckPage MsgBox "CheckPage" : CheckPage = True End Function Private Function CheckImage CheckImage = False Browser("title:=Welcome.*").WebElement("text:=Relevant Codes").Click 'Error here! MsgBox "Error!" 'This will not execute End Function 'This will not execute Private Function Login MsgBox "Login" End Function End Class Dim NewLogin : Set NewLogin = New Login
Above, the Result property of the Login Class is called, which first executes CheckPage, then CheckImage and finally Login. Note that Login will only execute if CheckImage runs without any errors.
Let’s create another class that calls the methods of the original Login class, but with the error handling capabilities of a Try-Catch-Finally statement. This is also the Class that will always execute the original Login class because that’s where the actual error handling using Try-Catch-Finally exists.
Try..Catch..Finally with Class_Initialize & Class_Terminate
Class LoginHandler 'LoginHandler start Public bResult Private Sub Class_Initialize Print "Entering Try.." & vbNewLine bResult = NewLogin.Result End Sub Private Sub CatchErr If Err.Number = 0 Then Exit Sub Print "Entering Catch.." Print "Error: " & Err.Description & vbNewLine Err.Clear End Sub Private Sub Class_Terminate : CatchErr Print "Exiting.." End Sub End Class 'LoginHandler end Set NewLoginHandler = New LoginHandler Set NewLoginHandler = Nothing Set NewLogin = Nothing
The Class_Initialize method of the class calls the Result property of the Login class. Once Result is called, it executes all the methods called by the Result property. If any error occurs, CatchErr is immediately called by Class_Terminate and later, all code inside the Class_Terminate method is executed.
Output of executing Login Class & LoginHandler:
QTP Print Log
Method Containing the Error?
By including the name of each method in the very first line, we can also find out where exactly the error occurred. This, however, I agree is quite time consuming and repetitive work. The only alternative to this has been shown by PowerDebug Beta. However, if you would like to extend the above approach in VBScript, this *may be* the only possible approach. I’ve been wrong before, and would love to see a technique which simplifies the method naming approach used below.
Login Class with Method Names
On Error Resume Next Class Login 'Login start Public sMethod Public Property Get Result Result = CheckPage And CheckImage And Login End Property Private Function CheckPage Me.sMethod = "CheckPage" MsgBox "CheckPage" : CheckPage = True End Function Private Function CheckImage Me.sMethod = "CheckImage" CheckImage = False Browser("title:=Welcome.*").WebElement("text:=Relevant Codes").Click 'Error here! MsgBox "Error!" 'This will not execute End Function Private Function Login 'This will not execute Me.sMethod = "Login" Msgbox "Login" End Function End Class 'Login end Dim NewLogin : Set NewLogin = New Login
LoginHandler (Outputs Method Names)
Class LoginHandler 'LoginHandler start Public bResult Private Sub Class_Initialize Print "Entering Try.." & vbNewLine bResult = NewLogin.Result End Sub Private Sub CatchErr If Err.Number = 0 Then Exit Sub Print "Entering Catch.." Print "Error occured in: " & NewLogin.sMethod Print "Error: " & Err.Description & vbNewLine Err.Clear End Sub Private Sub Class_Terminate : CatchErr Print "Exiting.." End Sub End Class 'LoginHandler end Set NewLoginHandler = New LoginHandler Set NewLoginHandler = Nothing Set NewLogin = Nothing
View code.
Output of executing Login Class & LoginHandler:
QTP Print Log
Notes
After using this technique for several days and manipulating it a bit from the original work, I have found some success. However, implementing Handler classes when the scope of the utility class increases can be quite challenging, and time consuming. I still believe its a start to something that we haven’t witnessed in QTP (yet). To be honest, I still prefer the old way of doing things where I can branch out most of my GUI code in conditional statements – which has enabled me to always create more comprehensive reporting.
My recommendation would be to use this approach with VBScript code instead of using it for QTP’s GUI objects, ofcourse, until absolutely necessary. Most of my usage for the above technique has been with pure VBScript code which has enabled me to create better error handling. In an upcoming article, I will show how this technique will be used to handle Excel errors and recover from them in the CatchErr method using a Select Case block. Including Try-Catch-Finally statements within Try-Catch-Finally statements is quite easily done in .NET, but its very complex to perform the same operation with VBScript. I’m still happy to have a start though.
If you have any questions, please ask them in the comments section.
{ 3 comments… read them below or add one }
We have been using Call Chain Mechamism and Error Handler combined since long… and it is working fine….
you can give your comparison comments
Varun,
I’m not sure I understand. Can you please show how you’ve used a Call Chain Mechanism to implement a Try-Catch-Finally??
Even I would also love to know how to implement this call chain mechanism.