Last Updated |
Jan 18, 2006 |
1.
Introduction
3.
Sources
and setup of dogtail
4.1.
Importing dogtail Libraries
4.2.
Load
Dogtail objects
4.5. Working
with application widgets
4.6. Get
/ Set Text field values
4.7.
Simulating
Widget
operations
4.8.
Building
Verification logic
4.9. Test Result Logging
4.10. Some
Useful Tips
dogtail is a GUI
test tool
and automation framework written in Python. It uses Accessibility
(a11y) technology to communicate with desktop applications. dogtail scripts
are
written in Python and executed like any other Python program. An
attempt has
been made, through this document, to help beginners to get started with
dogtail.
This
document is based on dogtail version 0.4.2.
2. Pre-requisites for dogtail:
Dependent packages for dogtail,
3. Source
and setup of dogtail:
The source
code for dogtail and pyspi is managed in the GNOME project's CVS
server.
Dogtail Sources:
http://cvs.gnome.org/viewcvs/dogtail/
Sample
scripts can be downloaded at http://cvs.gnome.org/viewcvs/dogtail/examples/
To build
dogtail, as root executethe following commands
./setup.py build
./setup.py install
A source tarball for pyspi
can be downloaded http://people.redhat.com/zcerza/dogtail/releases/pyspi-0.5.2.tar.gz
A source
tarball for dogtail can be downloaded from http://people.redhat.com/zcerza/dogtail/releases/dogtail-0.4.3.tar.gz
To setup ImageMagick,
after untarring the file, as root,
run the commands,
./configure,
#make
#make install
To Build
and install ElementTree, as root, run
./ElementTree.py
To install pyspi,
as root type,
./setup1.py
install --prefix=/usr
To install Pyrex,
Install Pyrex-0.9.3.1-1.src.rpm
a.
Build rpm from this SRPM,
rpmbuild
--rebuild
Pyrex-0.9.3.1-1.src.rpm
b. Install the
resultant
Pyrex-0.9.3.1-1.noarch.rpm in /usr/src/packages/RPMS/noarch/,
rpm
-ivh Pyrex-0.9.3.1-1.noarch.rpm
–nodeps
Dogtail
files tree (after installation):
Documents of dogtail
under - /usr/share/doc/python-dogtail/*
Dogtail is a test
automation
tool which uses accessibility feature of the underlying desktop. So it
is necessary to turn-on the accessibility feature while working with
Dogtail.
Say to turn on accessibility for Gnome Desktop from
the panel menu,
· Go to the desktop Preferences
menu ->
Preferences -> Accessibility -> Assistive Technology Support
· Ensure that the "Enable
assistive
technologies" checkbox is checked
OR
· Run the following
command:
gconftool-2 --set --type bool /desktop/gnome/interface/accessibility true
To start off with scripting,
4.1. Importing
dogtail libraries
At the beginning of every
dogtail script, the necessary libraries needs to be imported inorder to
use the functions defined in dogtail,
import
dogtail.config
import dogtail.tc
from dogtail.procedural import *
from dogtail.utils import screenshot
from os import environ, path, remove
environ['LANG']='en_US.UTF-8'
4.2. Load
Dogtail objects
The commonly
used objects for verification, and configuration in any dogtail scripts
need to be defined at the beginning of the script
DemoConfig
= dogtail.config.Config()
TestString = dogtail.tc.TCString()
TestImage = dogtail.tc.TCImage()
TestNumber = dogtail.tc.TCNumber()
More information on how these objects are used during scripting is explained in subsequent sections
Clearing of old test log files can be accomplished using the following command. This can be used at the beginning of the test script,
if
path.isfile(path.join(path.expandvars("$HOME"),
"Desktop", "<Filename>")):
remove(path.join(path.expandvars("$HOME"),
"Desktop", "<Filename>"))
4.4. Launching
an application
"Run" is the
command defined to launch any given application on the desktop.
Here the <application> needs to be substituted with the binary
name of the application you wish to launch
run('<application>'),
Eg:
run('gedit')
4.5. Working
with
application widgets
Focus.application
function is used to focus on the application window which is needed for
further action
focus.application('<application
name>'),
Eg:
focus.application('gedit')
4.6. Get/Set
text Field
Values
Functions which can be used to work with various text fields in applications are explained below:
Focus
on the
text area,
focus.text()
To
open a
file and read contents into a variable,
from
sys import path
demo = file(path[0] + '<path of file from present working
directory>')
Read
the
file into the text area by assiging the value of demo to
focussed widget
focus.widget.text
= demo.read()
Here,
demo
is a variable to read character by character of the file into the text
area,
path is the current
path from
where script is being executed.
4.7. Simulating Widgets
Operations
Toolbar
buttons can be operated after focus.application('<application
name>') by,
click('<button
name>'),
Eg:
click('Save').
Same applies for recursive for selecting the menu items,
Say for selecting "Quit" under menu "File" menu,
focus.application('<application
name>')
click('<menu name>')
Eg: focus.application('gedit')
Get the focus of the dialog so as to get all the widgets information,
focus.dialog('<Dialog
Name>'),
Eg:
focus.dialog('Save
as...')
After
getting the focus on the dialog, widget operations on the dialog is
possible,
To click the expandable buttons,
activate('<Button
name>'),
To
select
contents of table like in a 'Save As' dialog,
activate('<Widget
name>', roleName = 'role name'),
Eg:
activate('Desktop',
roleName = 'table cell')
To
set the
name in text boxes of dialogs,
focus.text()
focus.widget.text
= '<filename>',
Eg:
focus.widget.text
= 'UTF8demo.txt'
To
click on
the buttons,
click('<Button
filename>'),
Eg: click('Save')
4.8. Building
Verification logic
Verification
logic refers to the inbuilt verification that needs to be incorporated
in the script inorder to validate the actions performed in the script.
For example, in a dogtail script eog is made to open a image file, the
script needs to capture the image of the application and compare with a
baseline. This comparison will yield in "pass" / "fail" for a
particular test case.
Dogtail has
a few functions defined for building verification logic in the
scripts
Image
comparison, string comparison and number comparison.
String
Comparison: Compares
2 strings to
see if they are the same. The user may specify the encoding to which
the two
strings are to be normalized for the comparison. Default encoding
is the
default system encoding.
Syntax: compare(self,
label, baseline, undertest, encoding=Config.encoding)
Eg: TestString.compare(label,
baseline, testfile[i], encoding='utf-8')
Here label
is the line
being compared with baseline, the count of which increments string by
string.
Image
Comparison: Use
ImageMagick to
compare 2 files. This Calls ImageMagick's "compare" program. Default
compares are based on size but metric based comparisons are also
supported with
a threshold determining pass/fail criteria.
Syntax: compare(self,
label, baseline, undertest, dfile='default', metric='none',
threshold=0.0)
Eg: TestImage.compare(label,
baseline, testfile[i])
ImageMagick's
"capture" can be used to capture
images ( imagecapture function )
File
compare: Compares two text files line by line.
Open the
existing file1,
try:
file1 = open(path[0] + '<filename1>',
'r').readlines()
except
IOError:
print "File open failed"
Open
the
new file2,
filepath
= environ['HOME'] + '<filename2>'
testfile = open(filepath, 'r').readlines()
With
file1
and file2 opened as lists, compare them line by line to see if they are
the
same,
i =
0
for baseline
in file1:
label = "line test " + str(i + 1)
TestString.compare(label, baseline, testfile[i],
encoding='utf-8')
i = i + 1
Logging library needs to be imported for log enabling
.i.e., from
logging import LogWriter, TimeStamp.
Eg: if
path.isfile(path.join(path.expandvars("$HOME"),
"Desktop", "UTF8demo.txt")):
self.result = {"File Present": "PASS"}
LogWriter.writeResult(self.result)
Exception Handling: Any
exceptions thrown in the dogtail functions (libraries) can be caught
and
handled. This can suitably used for logging as well.
Eg. :
try:
file = open(path[0] + '/data/UTF-8-demo.txt', 'r').readlines()
except
IOError:
print "File open failed"
In the
above example, the open action of a file is placed
under try:. If there are any errors resulting in file not opening,
"File
open failed" will be printed.
For
condition: This is
used when there is a comparison to be
done in a loop like a string compare.
Eg. : file
comparison using string compare.
filepath
=
environ['HOME'] + '/Desktop/UTF8demo.txt'
testfile
=
open(filepath, 'r').readlines()
for
baseline in
gold:
label = "line test " + str(i + 1)
TestString.compare(label, baseline, testfile[i], encoding='utf-8')
i = i + 1
4.11. Some
useful Tips
The accessible information about the widgets can be used in dogtail
scripting. For eg., the rolename and the accessible name of a widget
can be obtained at-poke can be used in various dogtail widget functions
like "activate", "click" etc.
USING
Sniff
TO DO
Drag
n
Drop actions through dogtail:
TO DO
Writing
Application Wrappers
After the
completion of
scripting, the file is saved as
“<scriptname>.py”. Make sure python is
included in the path and accessibility is enabled.
To execute
the script,
type in the terminal
“python
<scriptname>.py”
This is the playback of the actions specified in the
dogtail script.
6.
Recording User
Actions
In the
examples folder
of dogtail installation is a recorder file, recorder.py. When
executed, this records all the actions happening on the
desktop OR on the application specified as the argument
for the "recorder.py".
To record
user actions,
invoke the application and run this script with application name as the
argument.
Eg.
: Launch gedit and to record, type 'recorder.py
gedit'
All
user
actions appear on the terminal. The terminal output can be
copied into a text file (.py) and modified by adding
import statements to get a executable dogtail
script.
Dogtail
provides user
certain configuration features to work at ease. Dogtail has a file,
config.py
which has all dogtail related configurations. For detailed
information on each of these parameters refer to the comments
in config.py installed as part of Dogtail libraries
(/usr/lib/python*/vendor-packages/dogtail).
Some
configurations
which a user can try setting in the config.py file are,
logdir
=
'/tmp/dogtail/logs/' # logs directory.
scratch
=
'/tmp/dogtail/' # temp directory.
basefile
= '' #
baseline file to load.
data
=
'/tmp/dogtail/data/' # location to save screenshots.
configfile
= ''
# The configuration file loaded.
searchBackoffDuration
= 0.5 # Duration of retry.
searchCutoffCount
= 20 # Number of retries for back-off algorithm.
defaultDelay
=
0.5 # Delay given by default in case of wait or sleep.
Complete
set of
variables can be got in the config.py file.
8.
Further Support
IRC:
#dogtail on irc.freenode.net
To subscribe to dogtail mailing lists,
goto http://mail.gnome.org/mailman/listinfo/dogtail-list
To post a message to all the list members, send email to dogtail-list@gnome.org.
Bugs can be filed in http://bugzilla.gnome.org
under dogtail category.
#!/usr/bin/env
python
# Preprocessor for python script
import dogtail.config
import dogtail.tc
from dogtail.procedural
import *
from dogtail.utils
import screenshot
from os
import environ, path, remove
environ['LANG']='en_US.UTF-8'
DemoConfig = dogtail.config.Config()
TestString = dogtail.tc.TCString()
TestImage = dogtail.tc.TCImage()
# Remove the existing log file, if it's still there from a
previous run
if path.isfile(path.join(path.expandvars("$HOME"),
"Desktop", "UTF8demo.txt")):
remove(path.join(path.expandvars("$HOME"), "Desktop", "UTF8demo.txt"))
# Invoke gedit.
run('gedit')
# Set focus on gedit
application
focus.application('gedit')
focus.text()
from sys import path
utfdemo =
file(path[0] + '/data/UTF-8-demo.txt')
focus.widget.text = utfdemo.read()
screenshot()
click('Save')
focus.dialog('Save as...')
activate('Browse for other folders')
activate('Desktop', roleName = 'table cell')
focus.text()
focus.widget.text = 'UTF8demo.txt'
click('Save')
click('Quit')
# To check if the saved file is the
same as
# the baseline file
try:
gold = open(path[0] +
'/data/UTF-8-demo.txt', 'r').readlines()
except IOError:
print "File open failed"
filepath
=
environ['HOME'] + '/Desktop/UTF8demo.txt'
testfile
=
open(filepath, 'r').readlines()
# Comparing them line by line to see
if they are the same
i = 0
for baseline in gold:
label = "line test " + str(i + 1)
TestString.compare(label, baseline, testfile[i], encoding='utf-8')
i = i +
1