| Version 3.4.4 |
| Jython and Groovy scripting |
This section explains technical details about the Jython integration in QF-Test and serves as a reference for the whole API exposed by QF-Test for use in Jython and Groovy scripts. For a more gentle introduction including examples please take a look at chapter 13.
| Module load-path (Jython) |
The load-path for Python/Jython modules, sys.path, is
assembled from various sources in the following order:
qftest/jython
qftest/qftest-3.4.4/jython/Lib
python.path
In addition, during 'Server script' or 'SUT script' node execution, the directory of the containing test-suite is prepended to the path.
The directory
qftest/qftest-3.4.4/jython/Lib contains
Jython-internal stuff, the complete Python library and the
following modules provided by Quality First Software GmbH: qfcommon.py,
qftest.py and qfclient.py. You should
not modify these files, since they may change in later versions of
QF-Test.
The directory qftest/jython is the place to put your
own shared modules. These will be left untouched during an update of
QF-Test. Modules that are specific to a test-suite can also be placed
in the same directory as the test-suite. The file extension for all
modules must be .py.
To add additional directories to the load-path, define the python.path
system property.
| The plugin directory |
Jython and Groovy can also be used to access Java classes and methods beyond the scope of QF-Test by simply importing such classes, e.g.
|
|
|
|||
|
| Example 37.1: Accessing Java classes from Jython | |||
The classes available for import are those on the CLASSPATH during
startup of QF-Test or the SUT respectively, all classes of the standard Java API and
QF-Test's own classes. For the SUT things also depend on the ClassLoader concept in use.
WebStart and Eclipse/RCP in particular make it difficult to import classes directly from
the SUT.
Additionally, there are plugin directories into which you can simply drop a jar file to
make it available to scripts. By default, the main plugin directory is called
plugin (big surprise here) and is located under QF-Test's root directory
qftest. This location can be overriden with the command line argument
-plugindir <directory>.
Jar files in the main plugin directory are available to both
'Server script' and 'SUT script' nodes. To make a jar
available solely to 'Server scripts' or solely to
'SUT scripts', drop it in the respective sub-directory called
qftest or sut instead.
| The package cache (Jython) |
In order to be able to import Java packages, Jython maintains a
cache of package information. By default this cache is located under
qftest/jython/cachedir. If this directory is not
writable, .qftest/jython-cachedir under the user's home
directory is used instead. The location of the directory can be
overridden with the python.cachedir system property.
When running QF-Test for the first time after installing it, you may see a number of messages of the form
*sys-package-mgr*: processing...
Later you should see these messages only when jar-files on the
CLASSPATH have been modified or new ones
added. Sometimes Jython goes into "hiccup mode" and regenerates
the cache for some jar-files every time QF-Test or the SUT is
started. In that case, simply remove the whole
qftest/jython/cachedir or
.qftest/jython-cachedir and the problem should go away.
| Initialization (Jython) |
During QF-Test and SUT startup an embedded Jython interpreter is
created. For QF-Test, the module named qftest is
imported, for the SUT the module named qfclient.
Both are based on qfcommon which contains shared code.
These modules are required to provide the run-context interface and
to set up the global namespace.
Next the load-path sys.path is searched for your
personal initialization files. For QF-Test initialization, the file
called qfserver.py is loaded, the file called
qfsut.py is used for the SUT. In both cases
execfile is used to execute the contents of these files
directly in the global namespace instead of loading them as
modules. This is much more convenient for an initialization file
because everything defined and all modules imported will be directly
available to 'Server scripts' and 'SUT scripts'. Note that
at initialization time no run-context is available and no
test-suite-specific directory is added to sys.path.
| Namespace environment for script execution (Jython) |
The environments in which 'Server scripts' or 'SUT scripts' are executed are defined by the global and local namespaces in effect during execution. Namespaces in Jython are dictionaries which serve as containers for global and local variable bindings.
The global namespace is shared between all scripts run in the same
Jython interpreter. Initially it will contain the classes
TestException and UserException, the
module qftest or qfclient for QF-Test or
the SUT respectively, and everything defined in or imported by
qfserver.py or qfsut.py. When assigning a
value to a variable declared to be global with the
global statement, that variable is added to the global
namespace and available to scripts run consecutively. Additionally,
QF-Test ensures that all modules imported during script execution are
globally available.
The local namespace is unique for each script and its lifetime is
limited to the script's execution. Upon invocation the local
namespace contains rc, the interface to QF-Test's
run-context, and true and false bound to
1 and 0 respectively for better
integration with QF-Test.
Accessing or setting global variables in a different Jython
interpreter is enabled through the methods fromServer,
fromSUT, toServer and toSUT.
| Run-context API |
The run-context object rc is an interface to
the execution state of the currently running test in QF-Test. Providing
this wrapper instead of directly exposing QF-Test's Java API
leaves us free to change the implementation of QF-Test without
affecting the interface for scripts.
Following is a list of the methods of the run-context object
rc in alphabetical order. The syntax used is a bit of a
mixture of Java and Python. Python doesn't support static
typing, but the parameters are passed on to Java, so they must be
of the correct type to avoid triggering exceptions.
If a parameter is followed by an '=' character and a value, that
value is the default and the parameter is optional.
Note
Please note that the Groovy syntax for keyword parameters is different from Jython and
requires a ':' instead of '='. The tricky bit is that, for example,
rc.logMessage("bla", report=true) is perfectly legal Groovy code yet
doesn't have the desired effect. The '=' here is an assignment resulting in the value
true, which is simply passed as the second parameter, thus the above is equal to
rc.logMessage("bla", true) and the true is passed to
dontcompactify instead of report. The correct Groovy version
is rc.logMessage("bla", report:true).
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The qf module |
In some cases there is no run-context available, especially when implementing some of
the extension interfaces described in the following sections. The module qf
enables logging in those cases and also provides some generally useful methods that
can be used without depending on a run-context. Following is a list of the methods of
the qf module in alphabetical order. Unless metioned otherwise, methods are
available in Groovy and Jython and for both 'Server script' and 'SUT script'
nodes.
Note
Please note that the Groovy syntax for keyword parameters is different from Jython and
requires a ':' instead of '='. The tricky bit is that, for example,
qf.logMessage("bla", report=true) is perfectly legal Groovy code yet
doesn't have the desired effect. The '=' here is an assignment resulting in the value
true, which is simply passed as the second parameter, thus the above is equal to
qf.logMessage("bla", true) and the true is passed to
dontcompactify instead of report. The correct Groovy version
is qf.logMessage("bla", report:true).
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Image API |
The Image API provides classes and interfaces to take screenshots, to save or load images or for own image comparisons.
| The ImageWrapper class |
For taking screenshots you can use the Jython class ImageWrapper, located in the module
imagewrapper.py, which comes with the QF-Test
installation.
Here is a short sample Jython script demonstrating the usage of the Image API:
|
|
|
|||
|
| Example 37.2: Image API in Jython | |||
And the same in Groovy:
|
|
|
|||
|
| Example 37.3: Image API in Groovy | |||
Following is a list of the methods of the ImageWrapper
class in alphabetical order. The syntax used is a bit of a
mixture of Java and Python. Python doesn't support static
typing, but the parameters are passed on to Java, so they must be
of the correct type to avoid triggering exceptions.
If a parameter is followed by an '=' character and a value, that
value is the default and the parameter is optional.
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Exception handling |
All QF-Test exceptions listed in chapter 31 are
automatically imported in Jython scripts and can be used for
try/except clauses like
try:
com = rc.getComponent("someId")
except ComponentNotFoundException:
...
When working with Groovy you must first import the exception:
import de.qfs.apps.qftest.shared.exceptions.ComponentNotFoundException
try {
com = rc.getComponent("someId")
} catch (ComponentNotFoundException) {
...
}
Only the following exceptions should be raised explicitely from
script code (with raise or throw new respectively):
UserException("Some message here...") should be
used to signal exceptional error conditions.
BreakException() or raise
BreakException("loopId") can be used to break out of a
'Loop' or 'While' node, either without
parameters to break out of the innermost loop or with the id
parameter to break out of a specific loop.
ReturnException() or raise ReturnException("value")
can be used to return - with or without a value - from a 'Procedure' node, similar
to executing a 'Return' node.
| Debugging scripts (Jython) |
Debugging scripts in an embedded Jython interpreter can be tedious. To simplify this task, QF-Test offers an active terminal window for communicating with each interpreter. These terminals are accessible through the »Clients« menu or through »Extras«-»Jython Terminal...«.
Alternatively, a network connection can be established to talk remotely to the Jython
interpreter - in QF-Test as well as within the SUT - and get an interactive command line.
To enable this feature you must use the command line argument -jythonport <number> to set
the port number that the Jython interpreter should listen on. For the SUT
-jythonport=<port> can be defined in the "Extra"
'Parameters' of the 'Start Java SUT client' or
'Start SUT client' node. You can then connect to the Jython interpreter, for
example with
telnet localhost <port>
Combined with Jython's ability to access the full Java API, this is not only useful for debugging scripts but can also be used to debug the SUT itself.
| Last update: 01/27/2012 Copyright © 1999-2012 Quality First Software GmbH |