GP/QTP Automation: Creating Dexterity Macro XML template
All related posts: Reference Page – GP/QTP Automation
Dexterity Macro Limitation
One of the major limitations identified in Dexterity Macro System is totally hard-coded data with no functionalities to read them from any external source. Running scripts that always look for exactly the same account number or check balance on always the same date would provide a little value for functional testing. While we can not change or add to functionality of Dexterity Macro, we can change macro file itself.
Solution
Since Dexterity Macros are required as a workaround for the cross-dictionary scripting issue, they are supposed to be executed in the context of the main test flow driven by testing script (VBScript in QTP). Thus, controller script may dynamically generate files from a template.
Requirements
A template for Dexterity Macro should have a structured recognition-friendly format, should be easily handled manually, provide parameterization instructions, and be expandable for any additional future functionalities.
If data for a parameterized step are not provided (empty string) the according step is not generated. That allows building flexible data entry script that skips not required GUI controls (they will retain the default value).
Using XML format in this case fulfills all the requirements.
Sample QTP script
Used resources:
Service Functions – XML (QTP, VBScript)
Using built-in and system dialogs in QTP
Service Script
' Input: Dexterity Macro file 'Output: XML template '---------------------------------- 'To open a dialog , for the user to select an xml file sRootPath = "<em>- define your root path here -</em>" Set objDialog = CreateObject( "UserAccounts.CommonDialog" ) objDialog.Filter = "Dexterity Macro Files|*.mac" objDialog.InitialDir = sRootPath & "Test Logic\" objDialog.FilterIndex = 1 intRC = objDialog.ShowOpen sFilename = objDialog.FileName 'extract macro file name Set regEx = New RegExp regEx.Pattern = "[^\\]{1,}\.mac" regEx.IgnoreCase = True regEx.Global = True Set Matches = regEx.Execute(sFilename) For Each Match in Matches sDestinationFileName = Match.Value Next Set regEx = Nothing Set Matches = Nothing ' Building the destination path for the xml file with the same name as the mac file strlen = Len(sDestinationFileName) sDestinationFileName = Left(sDestinationFileName,strlen-4) sDestinationPath = sRootPath & "<em>- define your subfolders here -</em>\" & sDestinationFileName &".xml" 'Create new XML File Set objXMLTemplate = XMLUtil.CreateXML("Template") Set objRoot = objXMLTemplate.GetRootElement objRoot.AddAttribute "type", "DexMacro" 'Open Macro text file '...not checking whether it exists Set FSO = CreateObject("Scripting.FileSystemObject") Set objMacFile = FSO.OpenTextFile(sFilename, 1) 'insert pre-defined commands Set objLine = CreateChildElementByName(objRoot, "Line", "") objLine.AddAttribute "type", "code" objLine.AddAttribute "data-driven", "Yes" ' by default objLine.AddAttribute "text", "Logging file %GP.Macro.Log.File" Set objDataNode = CreateChildElementByName(objLine, "Data", "GP.Macro.Log.File") objDataNode.AddAttribute "name", "GP.Macro.Log.File" 'Main loop - generating the template intLineCount = 1 Do While TRUE 'File is empty? boolRC = objMacFile.AtEndOfStream If boolRC Then Exit Do End If 'Get text line sLine = objMacFile.ReadLine() intLineCount = intLineCount + 1 'Comment or code ? If Trim(sLine) = "" Then sLine = "#--------------------------" End If If (Left(LTrim(sLine), 1) = "#") Then Set objLine = CreateChildElementByName(objRoot, "Line", "") objLine.AddAttribute "type", "comment" objLine.AddAttribute "text", sLine Else Set objLine = CreateChildElementByName(objRoot, "Line", "") objLine.AddAttribute "type", "code" objLine.AddAttribute "data-driven", "No" ' by default objLine.AddAttribute "text", sLine End If Loop objRoot.AddAttribute "linecount", CStr(intLineCount) objXMLTemplate.SaveFile sDestinationPath
Parameterization
Open generated XML file using available editor, for example, Microsoft XML Notepad.
Manually replace any character sequence representing parameterizable value with a unique (in the context of current line) identifier. Identifier should be preceded by “%” character. Manually create “Data” child nodes to map each identifier to a variable or cell name.
In the examples below parameterizable lines are highlighted.
Sample Dexterity Macro
ActivateWindow dictionary 'SmartList' form 'Account_Lookup' window 'Account_Lookup' MoveTo field 'PB_Advanced_Search' ClickHit field 'PB_Advanced_Search' NewActiveWin dictionary 'SmartList' form 'ASI_Advanced_Search' window 'ASI_Explorer_Criteria' ActivateWindow dictionary 'SmartList' form 'ASI_Advanced_Search' window 'ASI_Explorer_Criteria' MoveTo field 'ASI_Search_Field'[1] TypeTo field 'ASI_Search_Field'[1] , 'Account Number' MoveTo field 'ASI_Search_Type'[1] ClickHit field 'ASI_Search_Type'[1] item 2 # 'is equal to' MoveTo field 'ASI_Start_Account_Number':'Account_Segment_Pool1'[1] TypeTo field 'ASI_Start_Account_Number':'Account_Segment_Pool1'[1] , 111 MoveTo field 'ASI_Start_Account_Number':'Account_Segment_Pool2'[1] TypeTo field 'ASI_Start_Account_Number':'Account_Segment_Pool2'[1] , 1111 MoveTo field 'OK Button K' ClickHit field 'OK Button K'
Generated XML Template
<?xml version="1.0" encoding="utf-8"?> <Template> <Options type="DexMacro" linecount="35" wrap="'" /> <Line type="code" data-driven="Yes" text="Logging file %GP.Macro.Log.File"> <Data name="GP.Macro.Log.File">GP.Macro.Log.File</Data> </Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="No" text="ActivateWindow dictionary 'SmartList' form 'Account_Lookup' window 'Account_Lookup' "></Line> <Line type="code" data-driven="No" text=" MoveTo field 'PB_Advanced_Search' "></Line> <Line type="code" data-driven="No" text=" ClickHit field 'PB_Advanced_Search' "></Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="No" text="NewActiveWin dictionary 'SmartList' form 'ASI_Advanced_Search' window 'ASI_Explorer_Criteria' "></Line> <Line type="code" data-driven="No" text="ActivateWindow dictionary 'SmartList' form 'ASI_Advanced_Search' window 'ASI_Explorer_Criteria'"></Line> <Line type="code" data-driven="No" text=" MoveTo field 'ASI_Search_Field'[1] "></Line> <Line type="code" data-driven="No" text=" TypeTo field 'ASI_Search_Field'[1] , 'Account Number'"></Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="No" text=" MoveTo field 'ASI_Search_Type'[1] "></Line> <Line type="code" data-driven="No" text=" ClickHit field 'ASI_Search_Type'[1] item 2 # 'is equal to' "></Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="Yes" text=" MoveTo field 'ASI_Start_Account_Number':'Account_Segment_Pool1'[1] "> <Data name="account_segment1">account_segment1</Data> </Line> <Line type="code" data-driven="Yes" text=" TypeTo field 'ASI_Start_Account_Number':'Account_Segment_Pool1'[1] , %account_segment1"> <Data name="account_segment1">account_segment1</Data> </Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="Yes" text=" MoveTo field 'ASI_Start_Account_Number':'Account_Segment_Pool2'[1] "> <Data name="account_segment2">account_segment2</Data> </Line> <Line type="code" data-driven="Yes" text=" TypeTo field 'ASI_Start_Account_Number':'Account_Segment_Pool2'[1] , %account_segment2"> <Data name="account_segment2">account_segment2</Data> </Line> <Line type="comment" text="#--------------------------"></Line> <Line type="code" data-driven="No" text=" MoveTo field 'OK Button K' "></Line> <Line type="code" data-driven="No" text=" ClickHit field 'OK Button K' "></Line>
One response to "GP/QTP Automation: Creating Dexterity Macro XML template"
Hi Albert,
Your automation approach is totally different from the “common practices” promoted everywhere. Where did you learn it?
Can you give us more posts about automation methodology you use?
Brian
[ Albert’s reply.
Well, expanding the headline of my blog, it is an engineering and scientific approach, end-user oriented and situational feedback driven. I use what I learnt before, and I keep reading, learning, and thinking a lot.
I’m not stuck with a single methodology but I’ll definitely post more about what I use. ]