Table of Contents
One of Squish's most useful features is the ability to access the toolkit's API from test scripts. This gives test engineers sufficient flexibility to allow them to test just about any aspect of the AUT.
With Squish's Tk-specific API it is possible to find and query objects, access properties, and evaluate arbitrary Tcl code in the AUT's interpreter.
In addition, Squish provides a convenience API (see How to Use the Tk Convenience API (Section 5.6.4)) to execute common GUI actions such as clicking a button or selecting a menu item.
The How to Test Tk Widgets (Section 5.6.5) section later in this manual presents various examples that show how to use the scripting Tk API to access and test complex Tk widgets.
Squish provides the waitForObject
function
which returns a reference to the object with the given qualified object
name.
To find out the name of an object, you can use the Spy tool to introspect the application. See the How to Use the Spy (Section 5.21.3) section for details. Alternatively, record a quick throw-away test in which you interact with all the AUT objects you are interested in: this will populate the Object Map (Section 7.11) with the objects' names.
To get a reference to an object—which can then be queried to check
the object's properties, or which can be used to interact with the
object—use the waitForObject
function. For example, in Tcl you would use code like this:
set button [waitForObject "myapp.frame1.okbutton"]
If waitForObject
can't find the specified
object—or if the object is not available before the timeout, for
example if it is hidden—a script error is thrown which stops the
script execution. In some situations it might be desirable to check to
see if the object exists and only interact with the object if it is
found. This can be done by using the object.exists
function.
For example, suppose we want to find the okbutton
as we did
before, and click it—but only if it exists. In Tcl we can achieve
this with the following code:
if {[object exists "myapp.frame1.okbutton"]} { set button [waitForObject "myapp.frame1.okbutton"] invoke clickButton $button }
Using qualified object names with the waitForObject
function, means that test engineers
can query and interact with all the objects in the AUT's object
hierarchy.
Using the Tk script API it is possible to access almost all of Tk's widget properties.
For example, if we want to change the text in an entry
widget, we can do so using the following Tcl code, and of course,
substituting the qualified object name and the new text appropriately:
set entry [waitForObject "myapp.frame1.e1"] property set $entry text "New text" set text [property get $entry text] test log [toString $text]
The first two lines set the new text; the third line creates a new
variable, text
, and the last line prints the
text
to the Test Results (Test Results view (Section 8.2.18)).
Although Squish test scripts can access the Tk widget properties, this
is not sufficient for testing purposes, because not all the information
we want to query is available through these properties. Fortunately,
Squish provides a solution for this: the tcleval
function. This function can execute
arbitrary Tcl code which is interpreted within the scope of the AUT.
![]() | Only available with Tcl/Tk |
---|---|
This function is only available with Tcl/Tk applications, but not with Perl/Tk. |
For example, if we want to retrieve the contents of a Tk
text
widget, we cannot do so through the widget's
properties since the text is not available as a property. What we can do
instead is to call the text
widget's get
function, since this returns the text
widget's text between
given indices. So to get the entire text we use indices 1.0 and
end
. Here's how we can use the tcleval
function to call get
on a text
widget:
set text [invoke tcleval ".textfield get 1.0 end"]
Notice that the entire argument to tceval
is passed as a
string. The “.textfield” is the name of the
text
widget (recall that .
is the root of the
widget hierarcy in pure Tcl/Tk).
This section provides a glimpse of the script API Squish offers on top of Tk to make it easy to perform common user actions such as clicking a button. Details of the full API are given in the Tk Convenience API (Section 6.5) section of the Tools Reference Manual (Chapter 7). Here we will just show a few examples to give a taste of what the API offers and how to use it.
invoke clickButton [waitForObject \ ":addressbook\\.tcl.dialog.buttonarea.ok"] invoke type [waitForObject ":addressbook\\.tcl.dialog.email"] "com" waitForObjectItem ":addressbook\\.tcl.#menuBar" "File" invoke activateItem ":addressbook\\.tcl.#menuBar" "File" waitForObjectItem ":addressbook\\.tcl.#menuBar.#file" "Open..." invoke activateItem ":addressbook\\.tcl.#menuBar.#file" "Open..."
Here, we click a button, type some text into an entry widget, and invoke the File|Open menu option. These are the most commonly used Tk convenience functions, although there are additional ones in the API. For more examples of testing a variety of Tk widgets in AUTs see How to Test Tk Widgets (Section 5.6.5).
Table of Contents
This section illustrates how to test Tk applications using Tcl—and in particular, how to test some of the standard Tk widgets. Although only a few widgets are shown, the same principles and practices apply to all Tk widgets, so by the end of this section you should be able to test any of your AUT's widgets.
The most challenging aspect of implementing test scripts is usually when we want to create test verifications. As shown in the chapter Inserting Additional Verification Points (Section 4.1.1.4) in the Tutorial: Starting to Test Tk Applications (Section 4.10.1), this can be done using the Spy and its point & click interface. But in some cases it is actually more convenient—and more flexibile—to implement verification points directly in code.
To test and verify a widget and its properties or contents in code,
first we need access to the widget in the test script. To obtain a
reference to the widget, the waitForObject
function is used. This function finds the widget with the given name
and returns a reference to it. For this purpose we need to know the name
of the widget we want to test, and we can get the name using the Spy
tool (see How to Use the Spy (Section 5.21.3)) and adding the object to the Object Map (Section 7.11) (so that Squish will remember it) and then
copying the object's name (preferably its symbolic name) to the
clipboard ready to be pasted into our test. If we need to gather the
names of lots of widgets it is probably faster and easier to record a
dummy test during which we make sure that we access every widget we want
to verify in our manually written test script. This will cause Squish
to add all the relevant names to the Object Map (Section 7.11),
which we can then copy and paste into our code.
One common requirement is to test the state of a widget, in particular
whether it is enable or disabled. The widget's state
property holds the information we want—here are a couple of
examples that show it in use:
set entry1 [waitForObject ":myapp.entry1"] test compare [property get $entry1 state] "normal" set entry2 [waitForObject ":myapp.entry2"] test compare [property get $entry2 state] "disabled"
This code verifies that the entry1
widget is enabled and
that the entry2
widget is disabled.
Although the need to verify whether a standard Tk radiobutton or checkbutton is checked is a common requirement, neither of these widgets has a convenient property that we can use, so we must write a little bit more code than might have been expected.
We will start by verifying that a particular radiobutton is checked.
First we must retrieve the radiobutton's variable
and
value
properties, and then we must evaluate the variable to
see if it is equal to the value—if it is, then the radiobutton is
checked.
set radiobutton [waitForObject ":myapp.radiobutton"] set variable [property get $radiobutton "variable"] set value [property get $radiobutton "value"] set actual_value [invoke tcleval "return \$$variable"] test compare $actual_value $value
First we retrieve a reference to the radiobutton, then we retrieve the
two properties we are interested in. Next we evaluate the variable to
get its actual value using the tcleval
function, and finally we compare the actual value with the property
value to see if they're the same.
We must use a similar approach for checkbuttons, except that their
relevant properties are onvalue
and offvalue
.
set checkbutton [waitForObject ":myapp.checkbutton"] set variable [property get $checkbutton "variable"] set onvalue [property get $checkbutton "onvalue"] set actual_value [invoke tcleval "return \$$variable"] test compare $actual_value $onvalue
Here, we retrieve a reference to the checkbutton, and then to the
checkbutton's variable
and onvalue
properties.
And just like we did for the radiobutton, we evaluate the variable to
get its actual value, and compare this with the onvalue
to
see if they are the same.
If we wanted to verify that a checkbutton was not
checked, we would simply retrieve the offvalue
property and
compare that with the actual value—if they are the same, then the
checkbutton is not checked.
A standard Tk entry widget's contents can be queried using the
getvalue
property.
set entry [waitForObject ":myapp.entry"] test compare [property get $entry getvalue] "Houston"
Here we check that an entry contains the text “Houston”.
Querying the contents of Tk's multiline text widget is a bit
more involved. For that we must call the widget's get
method, giving it the start and end indexes for the text we want to
check.
set text [invoke tcleval ".textfield get 1.0 end"] test compare $text "line 1\nline 2"
Rather than retrieve a reference to the multiline text widget, instead
we have used the tcleval
function to
execute the widget's get
method with indexes that span the
entire contents—this will result in all of the widget's text being
returned. We then check that the text contains exactly two lines (with
texts, “line 1” and “line 2”).
Squish isn't limited to Tk's standard widgets—for example, we can test a BWidget Entry widget.
set bentry [waitForObject ":myapp.bentry"] test compare [property get $entry text] "Apollo"
Here we retrieve the BWidget's text using its text
property, and compare it to the text “Apollo”.
One common requirement is to check the text of a Tk listbox's active
item. This is easily done using the listbox's get
method.
set active [invoke tcleval ".listbox get active"] test compare $active "Gemini"
Similarly to what we did for the multiline text widget, rather than
retrieve a reference to the listbox, instead we have used the tcleval
function to execute the listbox's
get
method with an argument of
active
—this will result in the listbox's active
item's text being returned. We then compare the text as usual, in this
case with the literal text “Gemini”.
The iwidget Radiobox is different from the standard Tk radiobutton, in
that it has a getvalue
property that holds the text of its
currently checked radiobutton.
set radiobox [waitForObject ":myapp.rbox"] test compare [property get $radiobox getvalue] "Mercury"
If the Radiobox has radiobuttons, “Mercury”,
“Venus”, and “Mars”, we can verify that the
“Mercury” radiobutton is checked by retrieving a reference
to the Radiobox, and then comparing the value of its
getvalue
property to see if it matches the text of the
radiobutton that should be checked.