Descriptive Programming in QuickTest Pro

    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.
    The objects with which the user interacts are automatically identified by QTP and stored in a special repository. When saving 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 serial numbers. This method of identifying objects causes problems when playing autotests. Moreover, many objects do not get into the repository at all when recording. This is due to many reasons, the most common of which is complex layout or layout using DIVs. However, there is a way to access the objects of the application under test at the script execution stage, bypassing the repository.
    This method is called Descriptive Programming (DP).


    The main idea of ​​DP is to search for and access objects by their identification properties. For DOM elements, this can be ID, Name, Tag, Inner Text, etc. For example, to access a button with an Id equal to SubmitBtn, you need to 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 you used DP at some level of the hierarchy, then you cannot access the repository at the next hierarchy levels. For instance:
    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 constructs 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 will need QTP, a 14-day trial version can be taken here (requires HP Passport, registration is free).

    As the automation object, we again select Calculator
    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 "+" 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, see 60
    8. Press Ctrl + F12 to create the Output value of the test.
    9. In the window that appears, check the text property, by default, the value is saved in the data table cell. Click OK


    10. Close 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 case - excellent. But if we need to check not only multiplication, but also division, addition. And there are also negative numbers ... The option to forehead - to record 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 - if you add or remove buttons, you need to change the object repository.

    And here DP will come to our aid - each button has an inscription, which means you can identify the 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 do a unified action to check the calculator’s calculations.

    Create a new Action - Insert-> Call to new Action. Give her the name Calc_Tests and uncheck the Reusable Action checkbox. Move Calc_Tests in the Test Flow window above Action1.
    Next, we need to add parameters to the Action that we had originally, by default, Action1. In the TestFlow window, right-click on it-> Action properties-> Parameters. Add the OperList and Expected input string parameters and the ActualResult output string parameter.
    We modify the source code of Action1 as follows:
    operList = Parameter("OperList") ' получить входной параметр OperList
    expectedRes = Parameter("Expected") ' получить входной параметр Expected

    operArr = split(operList,";") ' разбить строку в массив по разделителю ;

    For each oper in operArr ' для каждого элемента массива
      Button_Click Window("Calculator"), oper ' нажать на заданную кнопку
    Next

    actual = rtrim(Window("Calculator").WinEdit("Edit").GetROProperty("text")) 'получить текущее значение результата

    If actual <> expectedRes Then
      reporter.ReportEvent micFail, "Calc Test","Expected: " & expectedRes & " <> Actual: " & actual ' запротоколировать результат
    else
      reporter.ReportEvent micPass, "Calc Test","Expected: " & expectedRes & " = Actual: " & actual
    End If


    Button_click Window("Calculator"), "C" ' сброс калькулятора
    Button_click Window("Calculator"), "MC" ' и памяти

    Parameter("ActualResult") = actual ' возврат актуального результата операции

    ' процедура нажатия на кнопку, идентифицированную по по ее свойству text
    Sub Button_click(Obj,btn_label)
      If Obj.WinButton("text:="& btn_label).Exist then ' если кнопка существует
        Obj.WinButton("text:="& btn_label).Click ' нажать ее
      end if
    End Sub


    * This source code was highlighted with Source Code Highlighter.

    Go to Calc_Tests and insert the call Action1: Insert-> Call to Existing Action–> Action1 Change the
    call line of Action1 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 character, and as described above: all DP expressions are regular expressions.

    You can add another case for verification. Calc_tests code might look like this:

    Dim actual
    RunAction "Action1", oneIteration, "1;2;\*;5;=","60,",actual
    ' экранирование * нужно потому, 
    'что * является специальным символом в регулярных выражениях.
    RunAction "Action1", oneIteration, "2;2;\+;5;=","27,",actual ' то же самое для +
    Window("text:=Calculator").Close
    ExitTest

    * This source code was highlighted with Source Code Highlighter.


    If you run the test, the calculator will do two calculations and the autotest will compare the expected and obtained results. As a result of the execution, we should get a progress report with “green ticks”;)

    Descriptive programming helps to solve problems that are either unsolvable or very laborious in the traditional approach.

    PS all involved with the holiday - the day of the Tester. Thanks

    PPS for karma, transferred to "Testing".


    Also popular now: