QuickTest Professional is a popular tool for automating functional testing. To a large extent, its popularity is due to the presence of a user activity recorder in it, which allows you to record user actions and convert them into a script.
Objects with which the user interacts are automatically identified by QTP and stored in a special repository - repository. When saved to the repository, QTP automatically saves the identification properties of the object, but does not always do this correctly. For example, if there are several tables on a web page (even if each of them has its own ID), QTP identifies them by sequence number. This method of identifying objects causes problems when playing AutoTests. Moreover, many objects do not get into the repository at all when writing. This is due to many reasons, the most frequent of which is complex layout or layout with the use of DIV-s. However, there is a way to access the objects of the application under test at the stage of script execution, bypassing the access to the repository.
This method is called Descriptive Programming (DP).
The main idea of ​​DP is the search and circulation of objects by their identification properties. For DOM elements, this can be ID, Name, Tag, Inner Text, etc. For example, to access the button with Id equal to SubmitBtn, use the following construction:
WebButton( "html tag:=button" , "html id:=SubmitBtn" )
* This source code was highlighted with Source Code Highlighter .
')
Calls to QTP objects are hierarchical. You can combine access to the repository and DP, but with one limitation - if DP was used at some level of the hierarchy, then you cannot access the repository at the next levels of the hierarchy. For example:
Browser( "Browser" ).Page( "Page" ).WebElement( "table1" ).WebElement( "html tag:=table" , "html id:=tbl_grid" ) '
Browser( "Browser" ).Page( "Page" ).WebElement( "html id:=table1" ).WebElement( "tbl_grid" ) '
* This source code was highlighted with Source Code Highlighter .
All search constructions in DP are regular expressions.
Browser( "Browser" ).Page( "Page" ).Link( "inner text:=Subject[\d]{1,2}" ) ' , inner text Subject, .
* This source code was highlighted with Source Code Highlighter .
Now let's play;).
We need QTP, a 14-day trial version can be obtained
here (HP Passport is required, registration is free).
As the object of automation, select Calculator again.
1. Run QTP.
2. Create a new test
3. Press the "Record" button.
4. In the window that appears, go to the Windows Application tab, click the "+" in it and enter calc.exe in the Application input field

5. Click OK.
6. In the automatically launched calculator, press the buttons 1,2, *, 5, =
7. In the result window we see 60
8. Press Ctrl + F12 to create the Test Output Value.
9. In the window that appears, put a tick in front of the text property; by default, the value is saved in a cell of the data table. Click OK

10. Close the Calculator.
11. Click Stop record in QTP
What did we get as a result? On the Expert View tab - our script
Window( "Calculator" ).WinButton( "1" ).Click
Window( "Calculator" ).WinButton( "2" ).Click
Window( "Calculator" ).WinButton( "*" ).Click
Window( "Calculator" ).WinButton( "5" ).Click
Window( "Calculator" ).WinButton( "=" ).Click
Window( "Calculator" ).WinEdit( "Edit" ).Output CheckPoint( "Edit" )
Window( "Calculator" ).Close
* This source code was highlighted with Source Code Highlighter .
For one test script - great. But if we need to check not only multiplication, but also division, addition. And there are also negative numbers ... The head-on option - to write down your Action for each case, has a significant drawback - it is difficult to maintain. A better option is to add all the buttons of the calculator to the repository and click on them programmatically.
A = "1"
Window( "Calculator" ).WinButton(A).Click
* This source code was highlighted with Source Code Highlighter .
The option is not bad, but it is very difficult to maintain it - if you add or remove buttons, you need to change the repository of objects.
And here DP comes to help us - each button has an inscription, which means it is possible to identify a button by it.
Window( "Calculator" ).WinButton( "text:=2" ).Click
* This source code was highlighted with Source Code Highlighter .
And in this case, we can write a universal procedure for pressing a button. Moreover, we can make a unified action to check the calculations of the calculator.
Create a new Action - Insert-> Call to new Action. Give her the name Calc_Tests and uncheck Reusable Action. Move the Calc_Tests in the Test Flow window above Action1.
Next, we need to add parameters to the Action that we originally had, by default Action1. In the TestFlow window, click on it with the right button-> Action properties-> Parameters. Add the input string parameters OperList and Expected and the output string parameter ActualResult.
We modify the source code for Action1 as follows:
operList = Parameter( "OperList" ) ' OperList <br>expectedRes = Parameter( "Expected" ) ' Expected <br><br>operArr = split(operList, ";" ) ' ; <br><br> For each oper in operArr ' <br> Button_Click Window( "Calculator" ), oper ' <br> Next <br><br>actual = rtrim(Window( "Calculator" ).WinEdit( "Edit" ).GetROProperty( "text" )) ' <br><br> If actual <> expectedRes Then <br> reporter.ReportEvent micFail, "Calc Test" , "Expected: " & expectedRes & " <> Actual: " & actual ' <br> else <br> reporter.ReportEvent micPass, "Calc Test" , "Expected: " & expectedRes & " = Actual: " & actual<br> End If <br><br><br>Button_click Window( "Calculator" ), "C" ' <br>Button_click Window( "Calculator" ), "MC" ' <br><br>Parameter( "ActualResult" ) = actual ' <br><br> ' , text <br> Sub Button_click(Obj,btn_label) <br> If Obj.WinButton( "text:=" & btn_label).Exist then ' <br> Obj.WinButton( "text:=" & btn_label).Click ' <br> end if <br> End Sub <br><br> <br> * This source code was highlighted with Source Code Highlighter .
Go to Calc_Tests and insert the call to Action1: Insert-> Call to Existing Action–> Action1
Change the Action1 call string to
RunAction "Action1" , oneIteration, "1;2;\*;5;=" , "60," ,actual
* This source code was highlighted with Source Code Highlighter .
The * character is escaped because it is a special regular expression symbol, and as written above: all DP expressions are regular expressions.
You can add another case to check. Calc_tests code might look like this:
Dim actual<br>RunAction "Action1" , oneIteration, "1;2;\*;5;=" , "60," ,actual<br> ' * , <br> ' * . <br>RunAction "Action1" , oneIteration, "2;2;\+;5;=" , "27," ,actual ' + <br>Window( "text:=Calculator" ).Close<br>ExitTest<br> <br> * This source code was highlighted with Source Code Highlighter .
If you run the test, the calculator will perform two calculations and the autotest compares the expected and obtained results. As a result of the execution, we should receive a performance report with green check marks;)

Descriptive programming helps to solve problems that in the traditional approach are either unsolvable, or very laborious.
PS all involved in the holiday - Testers Day.
PPS thanks for the karma, transferred to "Testing".