Table of Contents
In addition to the test-specific functionality that Squish provides, test scripts can also use the native functionality (including the standard libraries) provided by the scripting languages themselves. In this subsection we will show how to use native functionality to read data from an external file, write data to an external file, check for the existence of an external file, and delete an external file. In addition, we will see how to compare two external files, and also how to read the environment variables that are set when the script is running.
![]() | Python-specific |
---|---|
The Python examples don't show any Python import codecs, filecmp, os, subprocess, sys |
![]() | Perl-specific |
---|---|
The Perl examples don't show any Perl use File::Basename; use File::Spec; |
Table of Contents
Here we will see how to read data from an external file, write data to an external file, check for the existence of an external file, and delete an external file.
Reading an external file involves getting its complete filename (including path), and then reading it in the standard way that the scripting language supports. For example:
infile = findFile("testdata", "before.csv") infile = infile.replace("/", os.sep) test.log("Reading %s" % infile) file = codecs.open(infile, "r", "utf-8") lines = [] for line in file: lines.append(line) file.close() test.verify(len(lines) == 13)
infile = findFile("testdata", "before.csv"); infile = infile.replace(/[\/]/g, File.separator); test.log("Reading " + infile); file = File.open(infile, "r"); var lines = []; var i = 0; while (true) { var line = file.readln(); if (line == null) break; lines[i++] = line; } file.close(); test.verify(lines.length == 13);
my $sep = File::Spec->rootdir(); # Load data from an external file my $infile = findFile("testdata", "before.csv"); $infile =~ s,/,$sep,g; test::log("Reading $infile"); open(FILE, "<:encoding(UTF-8)", $infile) or test::fail("Failed to read $infile"); my @lines = <FILE>; close(FILE); test::verify(scalar(@lines) == 13);
infile = natify(findFile("testdata", "before.csv")) Test.log("Reading %s" % infile) lines = [] File.open(infile, "r:utf-8") do |file| file.each {|line| lines << line} end Test.verify(lines.length == 13)
set infile [file nativename [findFile "testdata" "before.csv"]] test log "Reading $infile" set fh [open $infile] set text [read $fh] close $fh set text [string trimright $text] set lines [split $text "\n"] test compare [llength $lines] 13
Here, we read a file called before.csv
that is in
the suite's (or the test case's) testdata
directory. The file is a text file using the UTF-8 encoding. We open the
file and read it line by line into a list (or array) of lines or into a
string which we then break into lines, depending on the scripting
language. And at the end we check that we have got exactly the number of
lines we expected.
Squish uses Unix-style path separators internally on all platforms,
but because we want to show the path to the user (using the test.log
function), we replace these with the
path separator that is appropriate for the platform (e.g.,
“\
” on Windows).
JavaScript has no native support for file handling or for operating system interaction, so Squish provides the File Object (Section 6.16.4) and the OS Object (Section 6.16.6) to fill these gaps.
Writing to an external file is simply a matter of creating a filename, opening the file for writing, and writing data to it in the standard way that the scripting language supports. For example:
outfile = os.path.join(os.getcwd(), os.path.basename(infile) + ".tmp") outfile = outfile.replace("/", os.sep) test.log("Writing %s" % outfile) file = codecs.open(outfile, "w", "utf-8") for line in lines: file.write(line) file.close()
outfile = infile + ".tmp"; var i = outfile.lastIndexOf(File.separator); if (i > -1) outfile = outfile.substr(i + 1); outfile = OS.cwd().replace(/[\/]/g, File.separator) + File.separator + outfile; test.log("Writing " + outfile); file = File.open(outfile, "w") for (var i in lines) file.write(lines[i] + "\n"); file.close();
# Save data to an external file my $outfile = File::Spec->rel2abs(basename($infile) . ".tmp"); $outfile =~ s,/,$sep,g; test::log("Writing $outfile"); open(FILE, ">:encoding(UTF-8)", $outfile) or test::fail("Failed to write $outfile"); print FILE @lines; close(FILE);
outfile = natify(File.join(Dir.getwd, File.basename(infile) + ".tmp")) Test.log("Writing %s" % outfile) File.open(outfile, "w:utf-8") do |file| lines.each {|line| file.write(line)} end
set outfile [file nativename [file join [pwd] [file tail "$infile.tmp"]]] test log "Writing $outfile" set fh [open $outfile "w"] foreach line $lines { puts $fh $line } close $fh
Here, we write a file that has the same basename as the file we read,
but with .tmp
appended (e.g.,
before.csv.tmp
), and save it into the script's
current working directory. Since we write exactly the same data as we
read, this file and the original should be identical. (We'll see how to
check this in a later subsection.)
Just as we did when reading a file, we replace the Unix-style path
separators with the path separator that is appropriate for the
platform. This is done purely for the output to the test.log
function; if we are not showing the
filename to the user we could safely use Unix path separators no matter
what the platform.
Here is an example that checks two files: the first is expected to exist and the second is not expected to exist.
test.verify(os.path.exists(infile), "infile correctly present") test.verify(not os.path.exists(outfile), "outfile sucessfully deleted")
test.verify(File.exists(infile), "infile correctly present"); test.verify(!File.exists(outfile), "outfile sucessfully deleted");
test::verify(-e $infile, "infile correctly present"); test::verify(!-e $outfile, "outfile sucessfully deleted");
Test.verify(File.exist?(infile), "infile correctly present") Test.verify(!File.exist?(outfile), "outfile sucessfully deleted")
test verify [file exists $infile] "infile correctly present" test verify [expr ![file exists $outfile]] "outfile sucessfully deleted"
We have used the two-argument form of the test.verify
function to provide more useful
detail information than simply “True expression”.
Removing an external file is easy—but not reversible!
os.remove(outfile)
File.remove(outfile);
unlink $outfile;
File.delete(outfile)
file delete $outfile
It would make sense to follow this with a call to the test.verify
function in conjunction with an
existence test to check that the file has been removed as expected.
To compare two external files, the easiest approach is to use the Comparing Files (Section 6.3.8.3) Squish API, but it is also possible to use the native script language features. It should not be necessary to use an external program like diff or fc.
# Compare using Squish API: test.compareTextFiles(infile, outfile) # Compare using Python API: test.verify(filecmp.cmp(infile, outfile, False), "infile and outfile equal according to filecmp library")
// Compare two external files: test.compareTextFiles(infile, outfile)
# Compare two external files test::compareTextFiles($infile, $outfile);
# Compare two external files Test.compareTextFiles(infile, outfile)
# Compare two external files test compareTextFiles $infile $outfile
We have to make our script account for the fact that we use the fc program on Windows and the diff program on other platforms. Fortunately, both programs exhibit the same behavior: if the two files are the same they return 0 to the operating system (0 is the traditional “success” value for programs) and if the two files differ they return 1. (They may return other values, e.g., 2, if an error in the command line they are given is encountered.)
Note that it is essential that the filenames use the correct path separators for the platform. We also put the filenames in quotes—except for the Tcl example—in case they (or their paths) contain spaces—something quite possible on Windows.
![]() | Python-specific |
---|---|
Python programmers can avoid using an external program and also the
inefficiency of loading entire files into memory by taking advantage of
the Python standard library's Python test.verify(filecmp.cmp(infile, outfile, False), "infile and outfile equal according to filecmp library")
The filecmp.cmp function returns a Boolean with
|
Here is an example of how to read some specific environment variables that might be set when the test script is running.
for key in ("HOME", "PATH", "MY_ENV_VAR"): test.log("%s = %s" % (key, os.environ.get(key)))
var keys = ["HOME", "PATH", "MY_ENV_VAR"]; for (i in keys) test.log(keys[i] + " = " + OS.getenv(keys[i]));
for my $key ("HOME", "PATH", "MY_ENV_VAR") { test::log("$key = $ENV{$key}"); }
ENV.each {|key, value| Test.log("#{key} = #{value}") }
global env foreach key {"HOME" "PATH" "MY_ENV_VAR"} { set value "" if {[catch {set value $env($key)}]} { # do nothing for missing key: empty default value is fine } test log "$key = $value" }
If you use a shell script or batch file as your AUT you can easily set some test-suite-specific environment variables which you can then access inside your test scripts using the technique shown here. (See Shell Scripts and .bat-Files as AUT (Section 7.3.4).) Note that test scripts do not have access to the AUT's environment variables (e.g., those set in the Test Suite Settings view (Section 8.2.16)'s Environment section).
Notice that for Python, using the dict.get
method ensures
that we get None
as the value of missing keys rather than
an exception. Similarly, for Tcl we achieve the same thing by catching
the exception that occurs if the looked up key is missing. For
JavaScript and Perl a missing key's value is a harmless empty value
which prints as an empty string.