16.11. Shared Data and Scripts

16.11.1. Storing and Locating Data- and Scriptfiles
16.11.2. Data-Driven Testing
16.11.3. Using Test Data in the AUT

This chapter discusses how to split tests into multiple files and how to share, access and use script and data files.

16.11.1. Storing and Locating Data- and Scriptfiles

Each test cases contains a default script file called test.<lang> (where <lang> can be one of py, js or tcl).

When creating more sophisticated tests, often many test cases may use common functionality. In Squish this is done by putting such functionality into a function in a separate script file which then can be used by multiple test cases.

Shared scripts are located in the shared/scripts folder of the test suite.

To create such a script file, just right click on scripts under shared in the test suite view and choose New Script

Then enter the name of the new file and press Enter. After that you can edit the new script file in the Squish IDE.

If you want to import an existing script into the shared script's folder of the test suite, just choose Import Script in the context menu instead.

After a shared script file has been created, it needs to be included by the test script of the test case.

To locate a script file, the findFile function can be used. The first argument to it is the type of file. In the case of a script file, we will use script. The second argument is the filename of the script. This function will search all possible locations (shared/scripts and SQUISH_SCRIPT_DIR and return the path of the file.

To include and evaluate a script file, the source function will be used.

As an example we assume that we created a function enterAddresses which enters some addresses into the address book AUT. We have put this function into the file enter_addr.<lang> under shared/scripts.

To include and call this function in the test.py of a Python test case, we would write:

def main():
    ....
    source(findFile("scripts", "enter_addr.py"))
    enterAddresses()
    ....

To include and call this function in the test.js of a JavaScript test case, we could use the following code:

function main() {
    ....
    source(findFile("scripts", "enter_addr.js"));
    enterAddresses();
    ....
}

To include and call this function in the test.tcl of a Tcl test case, the code would look like this:

proc main{} {
    ....
    source [findFile scripts "enter_addr.py"]
    enterAddresses
    ....
}

Test scripts are a special kind of test data. You can also use generic test data of any type such as a table with input and expected output data for example.

If a test data file should be only used by a single test case, it can be put into the testdata directory of the test case. If the test data should be shared so it can be used by multiple test cases, the data file can be put into the shared/testdata folder of the test suite

Additionally it is possible to create sub directories under the testdata directories to structure the test data.

Creating or importing a test data file is done as described above for the script files, just that the testdata directory is used.

To retrieve the filename of a test data file in a script, the findFile function can be used by passing testdata as first argument to it.

16.11.2. Data-Driven Testing

Data-driven testing is an approach where the test data (input and expected output) is separated from the test script code which contains the logic of the test. This means that the test data is read from a file or a database which contains data records. The test or a certain part of it is run for each data record.

The rationale behind this approach is to allow modifying a test (e.g. adding new data which the test should be run for) without having to modify the test's logic (test script). This enables to have test engineers without coding skills work on the content of a test (the data), while engineers with coding skills create the test logic (scripts).

Squish offers a special API to utilize test data for data-driven testing. Creating test data files has been discussed in the previous section. This section presents the script API to read and interpret test data.

Test data always contains data in a tabular format. By default Squish can read tab separated value files (TSV). In such a file, records are separated by new lines and fields are separated by tabs. The first record is used to describe the columns. Here is an exemplary TSV data file:

First Name	Last Name	Address	E-Mail	Number
Max	Mustermann	Bakerstreet 55	max@mustermann.net	1
John	Kelly	Rhodeo Drv. 678	jkelly@acompany.com	2
Joe	Smith	Queens Blvd. 37	joe@smith.com	3

This first line describes the table columns (First Name, etc). The other lines contain the actual data records. Fields are separated by tabs.

To open that file, read each record and print out the values, we can use the following Python code:

    for address_record in testData.dataset("addresses.tsv"):
        firstName = testData.field(address_record, "First Name")
        lastName = testData.field(address_record, "Last Name")
        address = testData.field(address_record, "Address")
        email = testData.field(address_record, "E-Mail")

        print("First Name:" + firstName)
        print("Last Name:" + lastName)
        print("Address:" + address)
        print("E-Mail:" + email)

In JavaScript the same looks like this:

    var set = testData.dataset("addresses.tsv");
    for (var address_record in set) {
        firstName = testData.field(set[address_record], "First Name");
        lastName = testData.field(set[address_record], "Last Name");
        address = testData.field(set[address_record], "Address");
        email = testData.field(set[address_record], "E-Mail");

        print("First Name:" + firstName);
        print("Last Name:" + lastName);
        print("Address:" + address);
        print("E-Mail:" + email);

Finally the same can be done in Tcl:

    foreach address_record [testData dataset "addresses.tsv"] {
	set firstName [testData field $address_record "First Name"]
	set lastName [testData field $address_record "Last Name"]
	set address [testData field $address_record "Address"]
	set email [testData field $address_record "E-Mail"]

        puts "First Name: $firstName"
        puts "Last Name: $lastName""
        puts "Address: $address""
        puts "E-Mail: $email""

So using testData.dataset(filename) a test data file is opened and a reference to the data file object is returned. The file is located using findFile internally, so for locating the file the rules as described in the previous chapter apply.

Using a for loop it is possible to iterate over each record of the data set. Using testData.field it is possible to read the value of a specified fields of the current record.

Using this API it is possible to execute script code for all records of a data file and use this external data instead of hardcoded data in the script.

A complete example of a data-driven test can be found in Creating a Data-Driven Test (Section 5.3) in the Tutorial: Creating the First Test with Squish for Qt (Chapter 5).

Finally it is also possible to import existing test data files (Excel and TSV files). You can either import the file using the context menu by right-clicking on the testdata item in the Squish IDE's test suite view or by just copying the file into the test data directory.

16.11.3. Using Test Data in the AUT

So far this chapter only talked about using test data in test scripts. Another usage case of test data is to provide files which the AUT itself should use or to retrieve files which the AUT created for verification.

As a first example let's assume that the addressbook AUT should load a file called customers.adr before executing further actions. The best way to store the customers.adr file is again the test case's or test suite's testdata directory.

To allow the AUT to open this file without the need to specify the path to this file (which can be different depending on the machine the test runs on), it is possible to copy the data file into the AUT's current working directory using testData.put. Additionally Squish will automatically clean up the data (remove the file) after the test completed.

Here is an example in Python which copies the file into the AUT's current working directory and then instructs the AUT to open this file:

def main():
    ....
    testData.put("customers.adr")
    findObject("Addressbook").fileOpen("customers.adr")

Often it is already necessary to have this file available in the AUT's current working directory when recording a test case. Given that the file already exists in a testdata directory, when choosing Test Suite|Record Test Case it is possible to choose test data files which should be copied into the AUT's working directory in the record settings dialog:

When recording a test case this way, the testData.put will be generated automatically in the recorded script.

Other case is to verify a file which has been generated by the AUT. Let's assume the addressbook AUT create a file newcustomers.adr after saving the addresses. In the script we want to compare this file with the existing customers.adr.

To retrieve the file from the AUT's current directory, we can use testData.get. Let's look the the following Tcl script as an example:

proc main {} {
    ....

    # call saveAs in the AUT
    set mainwindow [findObject "Addressbook"]
    invoke $mainwindow saveAs "newcustomers.adr"

    # retrieve saved file
    testData get "newcustomers.adr"

    # open and compare files
    set f1 [open [findFile "customers.adr]]
    set f2 [open [findFile "newcustomers.adr]]
    test compare [read $f1] [read $f2]

    ....
}

Additionally, using testData.exists it is possible to verify if a file exists in the AUT's working directory. Using testData.delete it is possible to remove a file from the AUT's working directory.