Overload your VBScript functions (My article on QAGuild)
Publication URL: http://www.qaguild.com/weekly_archives.php?UID=60
Code examples package: overload-codeexamples1
Overload your VBScript functions
While implementing Automated Functional Testing solutions I often face the challenge creating the scripts somewhat “intelligent”, capable of making decisions and recognizing different logical patterns on the run. One of the major steps on this path is breaking the boundaries of hard-coded logic and getting to the abstract programming level, – and the main abstract programming paradigm is Object-Oriented Programming.
Term function overloading in Object-Oriented Programming means implementation of more than one function under the same call name. The general advantages of this approach are the following.
- The code is more structured – following best practices
- Programming is more abstract – makes it closer to human logic
- Ability to implement default and optional parameters
- One less function to remember – better convenience in programming and maintenance
The main challenge implementing back-end of this approach is determining which function meant to be called. Something specific and unique in the context of the call must help to identify that – and call parameters serve this purpose.
VBScript is a simplified language with a lot of restrictions but its true power is an open support of the surrounding technologies. While such a core Object-Oriented features like polymorphism (that includes function overloading and overriding) and inheritance are not supported, external object families could be easily used within VBScript. One of the most useful objects is Dictionary.
Dictionary Object
Dictionary object represents a dynamic associative array with the following features.
- Item index (key) could be number or string (and must be unique)
- Item value could be of scalar type (single value, like number), or array type, string type, or even object reference
- Order of items doesn’t matter
- Items could be added or removed dynamically
- A key could be checked for presence
- Count of items is known
- The all defined keys could be exported into array
The presented features allow using Associative Programming technique and that in turn helps implementing polymorphism in function calls.
Objective (Example 1)
Implement QTP VBScript function changing Web Browser Window state from uncertain to the specified one.
- Target state: Maximized. Arguments: state = “MAX”
- Target state: Minimized. Arguments: state = “MIN”
- Target state: Resized. Arguments: state = “RESIZE”. Optional: Width (400), Height (300)
- Target state: Moved. Arguments: state = “MOVE”. Optional: X (0), Y (0)
- Target state: Closed. Arguments: state = “CLOSE”
- Target state: Navigated to address. Arguments: state = “NAVIGATE”. Optional: URL
Implementation
Declare the function as public; define local variables; initialize.
Public Function SetBrowser(ByRef objBrowser, ByVal objParameter)
Dim boolRC
Dim objBrowserWin, hWnd, intX, intY
Dim sTypeName, sState, sURL
'Verify parameters
sTypeName = TypeName (objParameter)
If sTypeName <> "Dictionary" Then
Set objParameter = CreateObject("Scripting.Dictionary")
End If
Verify target object (Browser Window) exists.
boolRC = objBrowser.Exist(0) If Not boolRC Then SetBrowser = FALSE Exit Function End If
Retrieve main argument and initialize it to default value if nothing was passed in.
'Retrieve arguments
sState = UCase(objParameter.Item("state"))
If sState = "" Then
sState = "MAX"
End If
Get Windows Handle of the Browser.
Perform operations based on the Actual State, Required State and Optional Parameters provided. Close the function.
'Get Browser as the Window Set objBrowserWin = objBrowser.Object hWnd = objBrowserWin.HWND
Select Case sState
Case "MAX"
On Error Resume Next
boolRC = Window ("hwnd:=" & hWnd).GetROProperty("maximized")
If Not boolRC Then Window ("hwnd:=" & hWnd).Maximize
Window ("hwnd:=" & hWnd).Activate
On Error GoTo 0
Case "MIN"
On Error Resume Next
boolRC = Window ("hwnd:=" & hWnd).GetROProperty("minimized")
If Not boolRC Then Window ("hwnd:=" & hWnd).Minimize
On Error GoTo 0
Case "RESIZE"
intX = IntVal(objParameter.Item("p.width"))
If intX <= 0 Then intX = 400
intY = IntVal(objParameter.Item("p.height"))
If intY <= 0 Then intY = 300
On Error Resume Next
boolRC = Window ("hwnd:=" & hWnd).GetROProperty("minimized") OR Window ("hwnd:=" & hWnd).GetROProperty("maximized")
If boolRC Then Window ("hwnd:=" & hWnd).Restore
Window ("hwnd:=" & hWnd).Resize intX, intY
Window ("hwnd:=" & hWnd).Activate
On Error GoTo 0
Case "MOVE"
intX = IntVal(objParameter.Item("p.x"))
If intX < 0 Then intX = 0
intY = IntVal(objParameter.Item("p.y"))
If intY < 0 Then intY = 0
On Error Resume Next
boolRC = Window ("hwnd:=" & hWnd).GetROProperty("minimized") OR Window ("hwnd:=" & hWnd).GetROProperty("maximized")
If boolRC Then Window ("hwnd:=" & hWnd).Restore
Window ("hwnd:=" & hWnd).Move intX, intY
Window ("hwnd:=" & hWnd).Activate
On Error GoTo 0
Case "CLOSE"
On Error Resume Next
objBrowser.Close
On Error GoTo 0
Case "NAVIGATE"
sURL = objParameter.Item("url")
On Error Resume Next
objBrowser.Navigate sURL
On Error GoTo 0
Case Else
'do nothing
End Select
Set objBrowserWin = Nothing
SetBrowser = TRUE
End Function
Additional Explanations
To avoid execution to be broken GUI interaction is wrapped by On Error statement.
Since changing the browser state is a service type operation (not a business functionality testing type) – the function does not report success or fail except of passing back the result.
Certain operations (resize, move) require specific window state – so the function sets the browser window to a normal state first.
Objective (Example 2)
Implement QTP VBScript function creating DOT NET GUI Object (ComboBox) initializing specified properties with defined or default values.
- Location: as defined or (0,0)
- Dimensions: as defined or (100,20)
- Prompt text: as defined or nothing
- Items: as defined or none
- Selected item: optionally defined by index or by value
Implementation
Declare the function as public; define local variables; initialize. Retrieve passed in parameters and initialize with default values.
Public Function CreateComboBox(ByVal objItems, ByVal objParameter)
Dim sText, intWidth, intHeight, intMaxLength
Dim intLeft, intTop
Dim objComboBox, objComboBoxStyle
Dim Iter, dvKeys, sItem, intIndex
'Verify parameters
If TypeName (objParameter) <> "Dictionary" Then
Set objParameter = CreateObject("Scripting.Dictionary")
End If
sText = objParameter.Item("p.text")
intWidth = InitLong(objParameter.Item("p.width"), 100)
intHeight = InitLong(objParameter.Item("p.height"), 20)
intLeft = IntVal(objParameter.Item("p.left"))
intTop = IntVal(objParameter.Item("p.top"))
Create object instance and set the properties.
Set objComboBoxStyle = DotNetFactory.CreateInstance("System.Windows.Forms.ComboBoxStyle", "System.Windows.Forms")
Set objComboBox = DotNetFactory.CreateInstance("System.Windows.Forms.ComboBox", "System.Windows.Forms") objComboBox.Text = sText
objComboBox.Width = intWidth
objComboBox.Height = intHeight
objComboBox.Left = intLeft
objComboBox.Top = intTop
objComboBox.DropDownStyle = objComboBoxStyle.DropDownList
Set objComboBoxStyle = Nothing
Define selectable items. If none specified – exit the function.
If TypeName (objItems) <> "Dictionary" Then Set CreateComboBox = objComboBox Exit Function End If dvKeys = objItems.Keys() For Iter = 0 To UBound(dvKeys) sItem = objItems.Item(dvKeys(Iter)) If sItem <> "" Then objComboBox.Items.Add(sItem) End If Next
If specified – set the item selected by default. Close the function.
If objParameter.Exists("p.index") Then
intIndex = IntVal(objParameter.Item("p.index"))
If intIndex <= UBound(dvKeys) Then
objComboBox.SelectedIndex = intIndex
End If
End If
If objParameter.Exists("p.item") Then
sItem = objParameter.Item("p.item")
intIndex = objComboBox.FindStringExact(sItem)
If intIndex <> - 1 Then
objComboBox.SelectedIndex = CInt(intIndex)
End If
End If
Set CreateComboBox = objComboBox
End Function
Additional Explanations
Certain low-level functions were used in the presented code examples:
Service Functions – String (QTP, VBScript)
See usage examples below.
‘Example (1)
‘Make sure you have the browser up and enabled
‘Do not confuse object recognition by running multiple browser windows
Set objBrowser = Browser("title:=.*","location:=0")
boolRC = SetBrowser(objBrowser, AssociateParameters("state = max"))
Wait 2
boolRC = SetBrowser(objBrowser, AssociateParameters("state = min"))
Wait 2
boolRC = SetBrowser(objBrowser, AssociateParameters("state = resize, p.width = 800, p.height = 600"))
Wait 2
boolRC = SetBrowser(objBrowser, AssociateParameters("state = move, p.x = 100, p.y = 100"))
Wait 2
boolRC = SetBrowser(objBrowser, AssociateParameters("state = close"))
‘Example (2)
Set objSelectEnvironment = CreateComboBox(AssociateParameters("1 = DEV1, 2 = DEV2, 3 = UAT"), AssociateParameters("p.prompt = Test Environment, p.left = 25, p.top = 50, p.item = DEV2"))
‘Now you can place ComboBox on the form if you have one
Analysis and conclusion
Overloading of functions is possible in VBScript and it does not actually require defining two separate functions.
Applying to Test Automation needs, the following common types of operations are the good candidates for implementation as overloaded functions.
- Perform different operations on the same object
- Perform same operations with the different types of input data
- Produce different output from the same input
- Initialize complicated data records in a generic way by implementing optional and default parameters
- All of the above in combinations
There is no need in spending hours guessing the all possible operations to cover in the overloaded function: they could be easily added later.
Since order of the pass-in parameters doesn’t matter new parameters won’t impact existing ones, and existing ones could be dynamically redefined based on the context. That creates additional convenience and reduces cost on tracking back changes in case of code refactoring.
Business functionality testing code becomes more compact and thus more readable and better maintainable. Minor level decisions are done automatically without putting additional coding efforts.
Combining function overloading with Layered Programming approach brings to an even higher level of abstraction in automated decision-making, and use of XML allows using of even more complicated associations – but this implementation is out of scope of the original article.
Related Posts

