JavaSwing Reference

Aus ExpeccoWiki

Wechseln zu: Navigation, Suche

This expecco plugin provides facilities to automate tests incorporating Java AWT/SWING applications. It also lets you access GUI components and other objects of a running Java Application, and to use and validate them in a test. In addition to single JavaSwing application tests, more advanced end-to-end scenarios are possible, where complex setups involving multiple Java-Swing apps, web-services, hardware and even mobile devices even combined can be controlled and tested from a single expecco test description.

Inhaltsverzeichnis

Features

  • Automated GUI testing of Java AWT/SWING applications
  • Parallel remote test-execution on multiple systems
  • Performs tests against completely built and executable Java applications. No source code changes / recompilation of the application is required
  • Access GUI components, using XPath-like locators.
  • Access Java objects of the application live at execution time. See JavaBridge Interface Library for more details about runtime object and Java VM access
  • Consists of an expecco block library and tools which help to model tests and inspect the GUI of the application

Installation

The JavaSwing testing plugin uses a so called "Java-Bridge" which consists of two parts: one side is a plugin for expecco, the other side is an extension to the Java execution environment (the "JavaBridgeAgent"). Expecco uses that bridge to communicate with the tested JavaSwing application.

Installing the Plugin in Expecco

The plugin is usually installed automatically by the installer; either included in the main expecco installation or provided as a separate installable add-on package. Its files are stored in the "plugin" subfolder of the expecco installation folder. You can also copy those files manually to that folder, if required. Expecco detects the plugin automatically during startup. So it may be required to restart any expecco session.

Setting up the JavaBridgeAgent

This section describes the steps needed to configure a test environment. Normally, this has to be done only once. If you have multiple installations of the Java Runtime Environment (JRE), the following procedure has to be repeated for every JRE you wish to use for testing.

  1. Copy the "JavaBridgeAgent.jar" into the "JRE_HOME/lib/ext" directory.
    • JRE_HOME: The JRE installation directory which you want to use for testing, for example: "C:\Program Files\Java\jre6" or "/opt/java/jre6".
    • "JavaBridgeAgent.jar" is found in the expecco plugin directory ("<<name not specified jet>>")
  2. Modify or create "JRE_HOME/lib/accessibility.properties" file and add or modify the line "assistive_technologies=...,JavaBridgeAgent"
    (the dots stand for whatever was there before, or empty. If there was no such line before in the properties file, add the line: "assistive_technologies=JavaBridgeAgent").
  3. Run your to-be-tested Java application with this "modified JRE" (see below).


Note: In the above pathnames, use "/" on unix machins, "\" on windows machines as path-separator.

Note: Executing the same application than once at the same time, on the same system can cause port conflicts and expecco might fail to setup an interprocess connection to it. To avoid this, specify a different port for each application. See "Defining the used communications port" below for details.

Note: If you have multiple JRE installations on your system, please ensure that the tested application is executed by the correct "modified JRE". To make sure that the "modified JRE" is used, execute the Java application via command line or set the system default JRE to the modified one.

We recommend giving the full path to the modified JRE in the command line:

'<your Java home directory>\bin\java.exe -jar "path to my application.jar" args'

Note: Some Java applications use their own JRE (for example, Open Office).

Note: You can also use the javaws tool to execute Java web start applications.

More info on JVM command line options are found in Java commandline options.

Defining the used communication-port

You can specify which TCP port number is used for the communicate between expecco and the JavaVM, by using one of the following mechanisms.

  1. Using the default TCP port ("4712")
    • If not specified otherwise, a default TCP port number is used. This default is OK, unless that port is in use by another application. You will get error messages complaining about not being able to connect if that is the case.
  2. Using a file
    • You can create a file named "javaBridgeProperties.txt" ("javaBridgepropertys.txt" in early versions of the bridge) in the "JRE_HOME/lib/ext" directory. Add the following line to the file:
    • "EXPECCO_JBRIDGE_PORT=<TCP_PORT_NUMBER>"
    • <TCP_PORT_NUMBER>: a value greater than 1024
    • Every application will then use the port as specified in this file.
  3. Using an environment variable
    • You can also specify the port in the shell-environment.
    • Set the environment variable: "EXPECCO_JBRIDGE_PORT" to a port greater than 1024.
    • Example: "set EXPECCO_JBRIDGE_PORT=3354" (windows) or "export EXPECCO_JBRIDGE_PORT=3354"

Hint: To start multiple applications on different ports, use method #3 from the above list. If it is not possible to set the environment for the application (for example, because it is started by some wrapping launcher), use method #2, and modify the port in the file after each application launch.

Disabling the Bridge (without deinstalling)

Once installed, the bridge will automatically hook itself into every Java application which is started in that modified JRE.

Of course, you can simply remove the whole modified JRE folder (if you were using a copy) and/or remove the added bridge-files to remove the bridge mechanism.

You also can rename the "accessibility.properties" file or delete this file altogether and/or the "JavaBridgeAgent.jar" from the "ext" directory. You can also remove the entry for the "JavaBridgeAgent" in the "accessibility.properties" file.

To disable the bridge without deinstallation, change the startup port to a value smaller than 1025. This forces the bridge to release and exit after startup, and leave the application alone.

Plugin Components

The bridge plugin consists of the following parts:

  • The Awt/Swing-browser, is used to explore your application.
  • The JavaSwingLibrary, provides blocks that you can use in your test-cases.
  • The JavaBridgeAgent, provides the interface between the tested application and your tests (i.e. expecco).

Element-Path

The Element-Path is a notation to describe the access-path to a component within the component tree of a Java Awt/Swing application. It is similar to XPath, as used in DOM-tree locators for web applications. An element's path can be retrieved via the AWT/Swing-Browser . In the test's action blocks, the component's path is used to specify its location (very similar how DOM elements are located in a web-test scenario). A path can contain dynamic parts and needs not to be absolute.

Note: The component tree might change during the execution of the application. For example, when a popup menu opens, the tree could be extended by dynamic menu-components and the path might change. In this case, use dynamic parts in the path or a path as retrieved when the popup menu was shown.

Specifying Paths

A typical path looks like:

/frame[@name='Notepad']/root pane/layered pane/panel/panel/panel/tool bar/push button[2]

This example describes the path to a tool bar, where the second button is selected. This is an absolute path.

The path is specified as a list of component identifiers. Each component identifier starts with a "/". A component identifier represents a node in the component tree. "/frame[@name='Notepad']" is the first component identifier for a JFrame. "/root pane" is the second component identifier and so on. The path is resolved by matching the children of a component against the current component identifier. In the example above, "frame" has one or more children. One of them is matching the "root pane". Again, "root pane" has one ore more children and one of them matches against the "layered pane" component identifier and so on.

The syntax of a component identifier is:

/<nodeIdentifier><[optional selector]>

Node Identifiers

The node identifier specifies which kind of component to look for at the current component tree position.

Available identifiers:

  • The role of the component.
    This results in one or more components matching the role of the components; for example, "push-button" for a button.
  • The "*" which matches any component
    Match the rest of the path against all child components at the current tree position.

Examples:

  1. Absolute path:
      "/frame[@name='Notepad']/root pane/layered pane/panel/panel/panel/tool bar/push button[2]"
  2. The same path with any components:
      "/*[@name='Notepad']/*/layered pane/panel/panel/panel/*/*[2]"

These two pathes will locate the same component in the previous example.

Selector (Index/Name)

The selector is optional and required to select an element from a locator where multiple components match. For example, if you have a panel with 3 buttons in it, you have to specify which of the 3 buttons to locate using a selector. The selector is enclosed in "[" and "]". The selector is resolved against the result of the node identifier match. This means if you have a component with two buttons and two combo boxes, and your identifier is the role pushbutton, then the selector is matched against the list of the two buttons.

Available selectors:

  1. The index selector
    Selects the component by its position in the match list. The syntax is "[index]", where index is one-based (1..)
  2. The @name selector
    Selects the component by its name. The syntax is "@name='<the name here>"

Examples:

//tool bar/push button[2]
Assuming that the tool bar contains at least two buttons, the second button is selected.
//tool bar/push button[@name='Save As...']
Again the second button is selected, here by its name.

Special Wildcard Notation

The // wildcard notation can be used to make a path much shorter and more flexible (also required, if dynamic component pathes exist). The "//" matches parts of the path and stands for "any sub path". As such, it can be seen like a super "*"-matcher: not only does it match single components along the path, but any sequence of arbitrary components is matched by it.

Example: Assuming that the full path to a "push-button"-component is:

/frame[@name='Notepad']/root pane/layered pane/panel/panel/panel/tool bar/push button[@name='Save As...']

If the application has only one button with the name "Save As...", it can be shortened to:

//push button[@name='Save As...']

If there is only one component with the name "Save As...", you can even write:

//*[@name='Save As...']

Alternatively, you replace only some parts of the path with this wildcard like this:

/*[@name='Notepad']//panel//tool bar/*[@name='Save As...']


Note: Use a path as short as possible, to allow for freedom with respect to changes in the layout. For example, the above shortened locators are more robust against added frames or other geometry changes in the application than the full path. However, be aware that it also increases the chances for multiple components to match the locator - and thereby also breaking your test. Some heuristics and experience is helpful in choosing a good locator.

AWT/Swing-Browser

The AWT/Swing-Browser is a tool to explore the component tree(s) of one or multiple currently executing Java application(s). It helps to explore the application and to develop your tests. A derived version of this browser is also used for the Android Component Browser.

Starting the Browser

If the plugin is installed in expecco you will have a button with a Java symbol available on the toolbar.

caption

This button starts the Awt/Swing browser. This browser handles multiple connections to multiple applications. It displays a component "'forest", consisting of one component-tree per connected application.

Connecting to the Application

To connect to your application, the JavaBridgeAgent must be installed and your application must be started as described at "Setting up the JavaBridgeAgent".

AwtSwingBrowserFileConnect.jpg

Select "File"->"Connect" to open the connect dialog.

AwtSwingBrowserConnectDialog.jpg

In the connect dialog, enter the address of the host on which the tested application is running. The host address can be either the host-name or the IP-address. The port must be the "EXPECCO_JBRIDGE_PORT" as configured in the target host's JRE (described above). If in doubt, reread the section "Setting up the JavaBridgeAgent".

Host - The target host name or its IP-address.
Port - The specified EXPECCO_JBRIDGE_PORT on the target host.

After the connection has been established, the component tree of all running applications on the target host is shown.

AwtSwingBrowserConnected.jpg

For each application, one subtree which starts at the top level window of each application is shown. The tree elements show a component's role followed by its name and value (if the component has a name or value). Select a component and press the right mouse button to open a context menu. The context menu performs its operations on the selected component(s).

Browser functions


Follow Cursor

Select the menu-item "Operations"->"Follow Cursor" to toggle the "follow-cursor" mode. If that mode is enabled, the browser's selection will follow the component under the mouse-pointer. If required, the tree will expand and/or scroll to make that component visible. Use this to find components in the browser tree, for which no locator is known (i.e. if the application is unknown/undocumented).

Verify Path

Use this function to optimize (i.e. shorten) a locator path. You can try alternative pathes and check if the new path still matches and returns the same component. To use this function, select a component in the browser's tree and select the "Verify Path" menu item in the context menu.
AwtSwingBrowserVerifyPath.jpg
You can modify the path in the input field and try alternative (shorter) pathes.
Verify Path
Verifies the path and displays information about the component matched by this path.
Reload Path
Reset and display the absolute path of the selected component.
Copy Path
Copy's the path to the clipboard.
Result View
Displays detail information about the located component. "Receiver:" is the component itself, "Children" are its direct descendends.

Actions

To display a component's actions, right-click and select the "Actions" item. Components which do have actions are marked by a blue "A" in the tree. To execute an action, select any from the shown list-of-actions and press "Execute".

Selection

If a component has selection capabilities, it is marked in the tree with a blue "S". RIght click and select "Selection" in the context menu.
In the selection screen, you see the currently selected indices and some information about them.
Select All
This selects all indices.
Clear All
Clears the selections.
Update
Shows the currently selected indices.
Add Indices
In the text input, enter indices separated by ",". Click on "Add Indices" to have them selected.
Remove Indices
Similar to "add indices", but removes the specified indices from the selection.

Table

Components with table functionality are marked with a blue "T" at the end in the tree. Right click and select "Table" from the context menu.
In the table screen, you see more detail information about a single row. To iterate through the rows, use the arrow buttons.
Get Header
Displays the header of the table.
Get Row At
Displays the specified row. To specify a row, enter the row's index into the input field to the right of the "Get Row At" button.

Text

Components with text are shown with a blue "T" at the second position in the tree. To see the text screen, select the component in the tree, and select the "Text" item from the context menu.
In the text screen, you can view and edit the text-contents of a component.
Get
This gets the currently displayed text of the component.
Set
To change the text of the component. To modify the text, edit the text in the input field.

Details

Details shows more information about a selected component. You see the "role", "name", "index" in parent, "bounds", "access" options, the current "states" and the "image path" of a component.

Grab Widget

This function captures a snapshot-image of the component's rendered contents. "Grab Widget" is useful to see what is currently displayed at a remote target host, and/or to fetch an image to be used in the text.
To see a component's currently rendered contents, select it in the browser tree and select "Grab Widget" from the right-button menu.

Mouse Events

In the mouse event screen, you can send simulated mouse & mouse-movement events to a component. To open it, select a component from the tree and then select the "Mouse Events" conetxt menu function.
Button
Select the mouse button you want to press.
Offset X and Y
The offset (in pixels) of the click position. The click position is relative to the upper left corner of the selected component. You can give both positive and negative values as offset.
Request focus
Sets the focus to the component.
Move mouse to position
This moves the mouse pointer to the position relative to the upper left corner of the selected component.
Press button
Moves the mouse pointer to a position and simulates a "press event" for the specified button.
Release button
Similar to "press button", but simulates a "release event".
Single click
Simulates a press and release in sequence.
Double click
Simulates two single clicks which are performed within a short time.

JavaSwingLibrary

With the operations described above you can explore a running Java Swing application. For automation and testing of an application, a library of building blocks is provided, which contains functional blocks for all of those operations.

AwtSwingLibraryImported.jpg

The JavaSwing Library consists of a set of predefined function blocks which are used to model your tests. Import this library via expecco's "Import Library" menu-function.

Predefined blocks

Initialization

Setup a Locator
A locator is an alias for a path to a component. It can be used to shorten the path expressions. Each locator will be expanded in a path expession.
identifier <String> - The identifier for your locator.
path <String> - The path to the component.
To use an locator as at a path input, write "@<your locator identifier here>". You also can use the locator as path part like this: "@<your locator identifier here><the rest of your path>".
Example: Use "@MyTabPaneLocator/page tab list[@name='Simple Widgets']/..." as path input.
Raise Window
Brings a window to the front by specifying a path to a component which is contained in the window.
bridgeID <String> - The host id you want to use.
path <String> - The path to the window or to one of its containing components.
Example: For a window path, write "/frame[@name='Notepad']" or "/frame" if it only has one window. Or use a path to one of the components of the window, like "//push button[@name='Save As...']".

Connection

connect to host
Establish a connection to a target host by its network address.
host <String> - The IP-network address or host name of the host you want to connect to. The default TCP port 4712 is used.
connect to host on port
Establish a connection to a target host by its network address and TCP-port.
host <String> - he IP-network address or host name of the host you want to connect to.
port <Integer> - The TCP port to use for the connection.
wait for Application
Wait for a window to appear with the given name and role.
bridgeID <String> - The host id you want to use.
applName <String> - The name of the window.
applRole <String> - The role of the window
timeoutSec <Integer> - Timeout for the window to appear.

Actions

execute action
Execute an action on a component.
bridgeID <String> - The host id you want to use.
path <String> - The path to the component on which to perform the action.
action <String> - The action to perform.

Mouse trigger

move mouse
Move the mouse pointer on the screen to a position relative to the upper left corner of a given component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where the pointer is moved to.
Optional: offsetX as Integer - A positive or negative offset which is added to the x coordinate of the upper left point of the component on the screen.
Optional: offsetY as Integer - A positive or negative offset which is added to the y coordinate of the upper left point of the component.
move & click left button
Move the mouse pointer on the screen to a position relative to the upper left corner of a given component and then performs a mouse click with the left mouse button at that position.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where the pointer is moved to.
Optional: offsetX as Integer - A positive or negative offset which is added to the x coordinate of the upper left point of the component on the screen.
Optional: offsetY as Integer - A positive or negative offset which is added to the y coordinate of the upper left point of the component.

Selection

select all
If the component supports selections, select all the items of the component. For example, if the component is a list which allows multiple items to be selected, then all the items of the list will be selected.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component whose elements should be selected.
name to selection index
If the component supports selections, this will return the index of the item which matches a given name.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where to look for the item with the given name.
nameOfElement <String> - The element name to look for.
Returns: index <Integer> - The found index.
get selected indices
If the component supports selections, this will return a collection of indices of the currently selected items of a component. If nothing is selected, an empty collection will be returned.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where to look for the selected items.
Returns: indices <OrderedCollection of Integers> - an empty collection is returned if nothing is selected. Otherwise the collection contains the indices of the currently selected items.
add index to selection
If the component supports selections, the item at the given index is added to the current selection.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where to select the item.
index <Number> - The item index which should be added to the selection.
clear selection
De-selects all the selected items of a component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component whose seletion should be cleared.

Widgets

CheckBox[set]
Set a checkbox to checked or unchecked.
bridgeID <String> - The host id you want to use.
path <String> - The path of the checkbox component.
enable <Boolean> - True: set the checkbox to checked. False: set it to unchecked.
CheckBox[get]
Returns if a checkbox is checked or unchecked.
bridgeID <String> - The host id you want to use.
path <String> - The path of the checkbox component.
Returns: enabled <Boolean> - True if the checkbox is checked or false if not.

Setup Entry Fields (Text,Numbers ...)

set text
Set the text of a text component to the given text.
bridgeID <String> - The host id you want to use.
path <String> - The path of the text component where to set the text.
contents <String> - The text to set.
set text lines
Set a multi-line-text of a text component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the text component where to set the text.
seqOfStrings <StringCollection> - The collection of texts which to set as text of the component. Each element of the collection represents one line of text.
get text
Return the text of a text component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the text component where to get the text from.
Returns: contents <String> - The text at the text component.
get current value
Return the value of a component which provides a value. For example a progress bar will return its progress value.
bridgeID <String> - The host id you want to use.
path <String> - The path of the component where to get the value from.
Returns: currentValue <String> - The current value of the component.
set number
Set a number as text on a text component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the text component where to set the text.
number <Number> - The number which will be set as text to the component.

Verification

VerifyPath
Check if the specified path addresses a component.
bridgeID <String> - The host id you want to use.
path <String> - The path that should be verified.
Returns: PathExists <Boolean> - Return true, if a component is found at the path, false otherwise.
Index from children with name
Check whether a component has childrenl If this is the case, return the index of a child component with a given name relative to its parent.
bridgeID <String> - The host id you want to use.
path <String> - The path of component where to look for the child.
name <String> - The name of the child component to look for.
Returns:
ChildFound <Boolean> - true, if the component has at least one child, false otherwise.
Index <Integer> - The index of the found child.

Fetch States
Return the current states of a component.
bridgeID <String> - The host id you want to use.
path <String> - The path of component where to get the states from.
Returns: states <Collection of Strings> - a list of the current states of the component.
Have State
Checks if a component has currently a given state.
bridgeID <String> - The host id you want to use.
path <String> - The path of component where to check the states.
Returns: haveState <Boolean> - true, if the component has the given state, false otherwise.

Table

get row (cells)
Return the names of the cells in a table row.
bridgeID <String> - The host id you want to use.
path <String> - The path of table component where to get the row from.
rowIndex <Integer> - The row index where to get the cells from.
Returns: values <StringCollection> - A list of cell names.
get number of table rows / columns
Return the number of columns and rows of a table component.
bridgeID <String> - The host id you want to use.
path <String> - The path of the table component, whose column and row count should be returned.
Returns:
numberOfColumns <Integer> - The number of columns in the table.
numberOfRows <Integer> - The number of rows in the table.

select table row(s)
Select one or more table rows of a table component.
bridgeID <String> - The host id you want to use.
path <String> - The path of table component where to select the row or rows.
rowNumber <Integer> - The row index. The cells of this row should be added to the selection.
addSelection <Boolean> - false, if the selection of the table is cleared before selecting. True, if the selected cells should be added to the current selection.
onlyRow <Boolean> - true, if the table has row selection enabled. then use true else false. Use this, if the table components selects a whole row even if only a single cell is selected. Otherwise set onlyRow to false. In this case the row is selected by iterating over each column in the row and adding it to the selection.
get selected rows (cells)
Return the values of the selected cells of a table component.
bridgeID <String> - The host id you want to use.
path <String> - The path of table component where to get the selected cell values from.
Returns: values <StringCollection> - A list of cell values.


Accessing Java Objects

You can interact with the Java objects as described at JavaBridge Interface Library. But first you need the so called "AgentManager" which manages the communication with your application under test. To get the manager use the following code.

|agentManager javaObject bridge|

agentManager := JavaSwing::JBridge getBridgeForHost:'localhost_4712'.

Replace 'localhost_4712' according to your connection configuration.

You can use the manager to get the Java proxy object by the path of a component.

javaObject := agentManager getJObjectForPath:'//text'.

Replace '//text' by the path of one of your component. This will return a Java proxy object which can be used as described at JavaBridge Interface Library.

To get the underlaying access bridge by the path of a component use this code.

bridge := agentManager getJavaBridgeForPath:'//text'.

Replace '//text' by the path of one of your component. This will return the bridge which was able to resolve the path. Now you can use the bridge as described at JavaBridge Interface Library.

Example

This is an example from a small notepad application which performs an undo by using the menu bar. NotepadUndoSample.png

The network to do that could look like this. SwingUndoSample.png

The first Step will open the "Edit" menu by a mouse click. Next "Undo" will be clicked. Then the text of the component which contains the text is retrieved. The retrieved text will be compared to the text "Hello JavaSwing". If the text matches each other, the test will be passed otherwise the test will be marked as failed.



Back to Online Documentation.

Meine Werkzeuge