Transitioning from Recorded Tests to Written Tests

Transitioning from Recorded Tests to Written Tests

New Squish users often begin their testing journey by record and playback of GUI tests. Recording a test script captures high-level interactions with your Application Under Test (AUT) instead of low-level events, like moving the mouse across the screen. The returned script is displayed in your preferred scripting language and can be played back, re-running through your steps as fast the application allows. With more confidence in scripting from initial recording sessions, you may want to transition your test creation methods to written tests from recorded tests. There are several advantages to this practice, discussed below.

We will use the simple addressbook application to illustrate the use of functions to simplify your test cases by reuse of common code blocks. This method will reduce the time spent in recording steps that appear more than once in a test case or across a test suite. Additionally, reformatting your test script into high-level functions will improve the readability of your test script. That is, a wall of object events will instead be shown by neat, compact function calls.

Our sample test case will first launch the AUT, create a blank addressbook file (.adr) and add contacts from a spreadsheet. We will first show the script generated from standard recording of each step listed above. Then, this script will be the guide for our creating functions from repeated steps (e.g., adding several contacts). 

def main():
    startApplication("addressbook")
    clickButton(waitForObject(names.address_Book_New_QToolButton))
    clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
    sendEvent("QMoveEvent", waitForObject(names.address_Book_Add_Dialog), 591, 292, 577, 210)
    type(waitForObject(names.forename_LineEdit), "John")
    type(waitForObject(names.forename_LineEdit), "<Tab>")
    type(waitForObject(names.surname_LineEdit), "Smith")
    type(waitForObject(names.surname_LineEdit), "<Tab>")
    type(waitForObject(names.email_LineEdit), "john.smith@hotmail.com")
    type(waitForObject(names.email_LineEdit), "<Tab>")
    type(waitForObject(names.phone_LineEdit), "+1 508 761 3829")
    type(waitForObject(names.phone_LineEdit), "<Return>")
    clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
    sendEvent("QMoveEvent", waitForObject(names.address_Book_Add_Dialog), 591, 292, 577, 210)
    type(waitForObject(names.forename_LineEdit), "David")
    type(waitForObject(names.forename_LineEdit), "<Tab>")
    type(waitForObject(names.surname_LineEdit), "Carson")
    type(waitForObject(names.surname_LineEdit), "<Tab>")
    type(waitForObject(names.email_LineEdit), "dcarson@gmail.com")
    type(waitForObject(names.email_LineEdit), "<Tab>")
    type(waitForObject(names.phone_LineEdit), "+1 243 019 7845")
    type(waitForObject(names.phone_LineEdit), "<Return>")
    clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
    sendEvent("QMoveEvent", waitForObject(names.address_Book_Add_Dialog), 591, 292, 577, 210)
    type(waitForObject(names.forename_LineEdit), "Gina")
    type(waitForObject(names.forename_LineEdit), "<Tab>")
    type(waitForObject(names.surname_LineEdit), "Banks")
    type(waitForObject(names.surname_LineEdit), "<Tab>")
    type(waitForObject(names.email_LineEdit), "banksg1@aol.com")
    type(waitForObject(names.email_LineEdit), "<Tab>")
    type(waitForObject(names.phone_LineEdit), "+1 978 894 4325")
    type(waitForObject(names.phone_LineEdit), "<Return>")
    clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
    sendEvent("QMoveEvent", waitForObject(names.address_Book_Add_Dialog), 591, 292, 577, 210)
    type(waitForObject(names.forename_LineEdit), "Steph")
    type(waitForObject(names.forename_LineEdit), "<Tab>")
    type(waitForObject(names.surname_LineEdit), "Parker")
    type(waitForObject(names.surname_LineEdit), "<Tab>")
    type(waitForObject(names.email_LineEdit), "parker@outlook.com")
    type(waitForObject(names.email_LineEdit), "<Tab>")
    type(waitForObject(names.phone_LineEdit), "+1 774 872 2192")
    type(waitForObject(names.phone_LineEdit), "<Return>")
    clickButton(waitForObject(names.address_Book_Unnamed_Save_QToolButton))
    sendEvent("QMoveEvent", waitForObject(names.qFileDialog_QFileDialog), 383, 163, 529, 206)
    type(waitForObject(names.fileNameEdit_QLineEdit), "book01demo")
    type(waitForObject(names.fileNameEdit_QLineEdit), "<Return>")
    sendEvent("QCloseEvent", waitForObject(names.address_Book_book01demo_adr_MainWindow))

Predictably, the UI events for creating each new contact are identical, save for the contact person’s details. Adding a contact follows the below format (please review the comments embedded in the script):

    # click to add a new contact
    clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
    # set the first name
    type(waitForObject(names.forename_LineEdit) , firstName   )
    # tab over to the next input field
    type(waitForObject(names.forename_LineEdit) , “<Tab>”     )
    # set the last name
    type(waitForObject(names.surname_LineEdit)  , lastName    )
    # tab over to the next input field
    type(waitForObject(names.surname_LineEdit)  , “<Tab>”     )
    # set the email address
    type(waitForObject(names.email_LineEdit)    , emailAddress)
    # tab over to the next input field
    type(waitForObject(names.email_LineEdit)    , “<Tab>”     )
    # set the phone number
    type(waitForObject(names.phone_LineEdit)    , phoneNumber )
    # issue a return to save the new contact
    type(waitForObject(names.phone_LineEdit)    , “<Return>"  )

We would like to repeat the same steps, but instead of entering contacts one by one, we will import multiple contacts from a comma separated text file. We will achieve this via a compact Python function. 

def addContacts(fileName):
    # create a new addressbook:
    clickButton(waitForObject(names.address_Book_New_QToolButton))
    # loop over lines in the .txt file:
    for line in open(fileName):
        # split each line by a comma separator:
        firstName, lastName, emailAddress, phoneNumber = line.split(",")
        # click to add a new contact:
        clickButton(waitForObject(names.address_Book_Unnamed_Add_QToolButton))
        # set the contact info:                           # strip whitespace    
        type(waitForObject(names.forename_LineEdit) , firstName.strip()    ) 
        type(waitForObject(names.forename_LineEdit) , "<Tab>"              )
        type(waitForObject(names.surname_LineEdit)  , lastName.strip()     )
        type(waitForObject(names.surname_LineEdit)  , "<Tab>"              )
        type(waitForObject(names.email_LineEdit)    , emailAddress.strip() )
        type(waitForObject(names.email_LineEdit)    , "<Tab>"              )
        type(waitForObject(names.phone_LineEdit)    , phoneNumber.strip()  )
        type(waitForObject(names.phone_LineEdit)    , "<Return>"           )

The function, addContacts, calls the comma separated text file containing the list of contacts. Using a for loop, we loop over each line in the spreadsheet, splitting it by the comma separator. Then, the type events are included in the last portion of the function to enter in the data, line by line. This function, with comments, is neatly tucked away in a global script. Additionally, for tens or hundreds of contacts, we’re still left with calling this function only once. Our Squish test case now looks like this:

def main():
    # source global scripts
    source(findFile("scripts", "addressbook01.py"))
    # start the AUT
    startApplication("addressbook")
    # import contacts from addressbook
    addContacts(”addressbook-contact-table.txt”)

Which is just four lines. 

This method of modelling your UI interactions by functions is beneficial in different ways. First, your script is often shorter and more organized. Second, it offers improved readability and easier debugging. Third, for repetitive tasks or interactions needed in more than one test case within a large suite, these functions can be easily called from a single global script, thus greatly saving on time. 

0 Comments

Leave a reply

Your email address will not be published. Required fields are marked *

*