Jemmy Tutorial

Contents


Introduction

This tutorial below doesn't expose Jemmy functionality very much. It mostly shows how to use the most hi-level jemmy part - operators. It also provides some references to the lower-level functionality.

Window searching

To do anything with swing component, you have to find it first. To find component you first have to find a window containing it.

Note: Neither component nor window searching doesn't have a practical meaning in most cases. So now, below when we really mean "wait" we say "find." Low-level functionality is implemented in org.netbeans.jemmy.ComponentChooser and org.netbeans.jemmy.WindowWaiter classes.

The most typical scenario is when a frame or dialog is searched by title. Both org.netbeans.jemmy.operators.JFrameOperator and org.netbeans.jemmy.operators.JDialogOperator have constructors with java.lang.String parameter which allow to find a frame or dialog. Dialog also can be found between its parent children if we know the parent.

Component searching

As soon as we have found a window, we have a starting point to find a component. Components can be searched inside the container. org.netbeans.jemmy.operators.ComponentOperator and all its subclasses (except operators for window-like components) have constructors with org.netbeans.jemmy.operators.ContainerOperator parameter. The rest of the parameters differ from component to component. Most operators have constructors with java.lang.String parameter which defines a component string resource value.

Note: Components also can be found by an ordinal index or by a string and an index. The way to compare strings during searching:

   org.netbeans.jemmy.operator.Operator.StringComparator
   org.netbeans.jemmy.operator.Operator.setDefaultStringComparator(org.netbeans.jemmy.operator.Operator.StringComparator)
   org.netbeans.jemmy.operator.Operator.setComparator(org.netbeans.jemmy.operator.Operator.StringComparator)

Access to swing component

Having an operator, you can get a component by org.netbeans.jemmy.operators.ComponentOperator,getSource() method. But, all operators map all components methods: org.netbeans.jemmy.operators.AbstractButtonOperator.getText() maps javax.swing.AbstractButton.getText(). The difference between ((AbstractButton)abstractButtonOperator.getSource()).getText() and abstractButtonOperator.getText() is that an operator invokes getText() through the event queue. So, normally it's better to use an operator's methods to access components. It gives more test stability.

Note: Operator's mapping method cannot be used if the code itself is executed inside the queue. Using an operator's mapping method will result in a deadlock in this case.
Note: Behavior described above is used by default. You can, though, change it. See Event queue using for more info.

Actions with component

org.netbeans.jemmy.operators.ComponentOperator contains all methods simulating user input by mouse and keyboard operations. Other operators contain most methods necessary to drive components.

Nonblocking actions

This section applies to non-robot mode only. Robot operations work well when either any modal dialogs are displayed or not. Run the ModalDialogSample.java sample both in robot and nonrobot node to see this. If a modal dialog is showed as a result of an action (such as button pushing), the push method will never end and thus, test execution will be blocked. In this case, one of the nonblocking methods have to be used:

org.netbeans.jemmy.operators.AbstractButtonOperator.pushNoBlock()
org.netbeans.jemmy.operators.AbstractButtonOperator.changeSelectionNoBlock(boolean)
org.netbeans.jemmy.operators.JMenuBarOperator.pushMenuNoBlock(ComponentChooser[])
org.netbeans.jemmy.operators.JMenuBarOperator.pushMenuNoBlock(String[])
org.netbeans.jemmy.operators.JMenuBarOperator.pushMenuNoBlock(String path, String delim)
org.netbeans.jemmy.operators.JMenuOperator.pushMenuNoBlock(ComponentChooser[])
org.netbeans.jemmy.operators.JMenuOperator.pushMenuNoBlock(String[])
org.netbeans.jemmy.operators.JMenuOperator.pushMenuNoBlock(String, String)
org.netbeans.jemmy.operators.JPopupMenuOperator.pushMenuNoBlock(ComponentChooser[])
org.netbeans.jemmy.operators.JPopupMenuOperator.pushMenuNoBlock(String[])
org.netbeans.jemmy.operators.JPopupMenuOperator.pushMenuNoBlock(String, String)

Note: Indeed, any blocking action should be just executed in a separate thread. So if you have a testcase where a modal dialog is shown, but Jemmy does not provide such kind of nonblocking operation, you will have to create the thread yourself. Either way is good, but we recommend to override the org.netbeans.jemmy.operators.Operator.NoBlockingAction class and run it using the org.netbeans.jemmy.operators.Operator.produceNoBlocking(NoBlockingAction,Object) or the org.netbeans.jemmy.operators.Operator.produceNoBlocking(NoBlockingAction) method.

Using the Event queue

Since all GUI updates normally go though the event queue, it can be used for the test stabilization purpose.

Note: If, during execution, the application does not update its GUI periodically, then the GUI may only change after some user input. So, if the queue is empty, we can be sure that user input has been processed completely, and thus, we can post other input operations. If the application does run something, we cannot be sure of this.
Note: org.netbeans.jemmy.QueueTool class provides some more functionality such as wait for the queue be staying empty during certain time.

Jemmy exceptions

Any unsuccessful operation in Jemmy exits with an exception. All exception classes extend org.netbeans.jemmy.JemmyException.

Note: Here's a tip on how to use Jemmy functionality in a negative way. You could insert an operation which shouldn't work in a try-catch block.

String resources

String resources like button text, window titles, tree paths, ... could be moved into special resource files. It saves you from changing all the tests in case just the application's window title was changed. Also it requires just one set of tests for all languages supported by the application. You can load resources from a file by using the org.netbeans.jemmy.Bundle.loadFromFile(String) method.

Note: Implementation is in two classes: org.netbeans.jemmy.Bundle and org.netbeans.jemmy.BundleManager

Drivers

This is definitely low-level functionality, and normally it's not something test developer should take care about. Starting from Jemmy 2.0 operators behavior is defined by a set of classes called "drivers" (org.netbeans.jemmy.drivers package). For instance, button pushing is performed by ButtonDriver implementation, which has press, release and push methods. The implementation could do pushing using mouse, keyboard, or just invoke AbstractButton.doClick() method. By default Jemmy uses a set of drivers allowing it to work exactly the same way Jemmy 1.0 working. Practically, depending on you specific system requirements you might want to change some of the existing drivers to perform user actions reproducing model. You can even create you own drivers - just implement one of the *Driver interfaces and register you driver by one of the DriverManager methods. Do this registration before any other test action so all the created operators will use registered drivers.

Timeouts

All GUI operations take time, so a test running in it's own thread, mostly waits for something to happened. Jemmy has a lot of timeouts for different types of waiting. All timeouts used by a class are usually described in javadoc (you can see them in the class' page title).

Note: If waiting was not finished successfully in an appropriate time, org.netbeans.jemmy.TimeoutExpiredException will be thrown.

There also is another type of timeout - sleeping timeouts. For different purposes (like demo or test debugging) it's useful sometimes to increase them. Default values for all sleeping timeouts are 0, except Waiter.TimeDelta (see below).

Examples of timeouts:

  • ComponentOperator.PushKeyTimeout - time to sleep between key pressing and releasing.
  • Waiter.TimeDelta - default time to sleep between attempts.
  • WindowWaiter.WaitWindowTimeout - maximum time to wait window.
  • JTreeOperator.WaitNodeExpandedTimeout - maximum time to wait next node loaded during tree operations

Timeouts values can be stored in file in properties format:

Waiter.TimeDelta=1
WindowWaiter.WaitWindowTimeout=180000

You can load them using the org.netbeans.jemmy.Timeouts.load(String) method.

Robot vs event dispatching

Starting from 1.3, Java has included the java.awt.Robot class which generates native system input events for the purposes of test automation. Jemmy test can be executed using Robot, as well as without. In the second case, Jemmy dispatches events directly to components working with. So, what's the difference? Obviously, Robot mode is more "honest." If something cannot be done manually, it cannot be done automatically. This gives us a certainty the only tests that passed are the ones that can be reproduced manually. And there is no such thing as, what cannot be done by robot mode can only be done manually.
On the other hand, "dispatching" mode does not care about any window could be opened by the window manager even if it completely closes the application's windows. It can work on locked display (it depends on operating system and window manager). It is also a little faster. "Dispatching" mode is used by default. You can change it this way:

   JemmyProperties.setCurrentDispatchingMode(JemmyProperties.ROBOT_MODEL_MASK)

Or from command line:

   java ... -Djemmy.robot_dispatching=on ...

Timeouts and resources location

Jemmy recognize one more option from command line: jemmy.properties. Value of this option must be file name containing two (or just one of them) strings:

TIMEOUTS_FILE=[file containing timeouts]
RESOURCE_FILE=[file containing string resources]

These string defines files to load timeouts and string resources resources from.

Test execution

Tests are usually executed using a test harness program which provides execution by a list of test, test monitoring, tests result formatting, and so on. Use your harness documentation to find out how to organize your tests. If it can implement org.netbeans.jemmy.Scenario interface, though, it can be executed from command line directly:

 java -classpath [jemmy classes]:[test classes]:[application classes] [aplication options] [jemmy options] org.netbeans.jemmy.Test [test class] [test parameters]

Test stability

GUI tests are unstable - that's a reality. Imagine if the network was very busy when a test was waiting for the window which loads something through the network during creation. How long should the test wait for the window? How soon it should give up? We have a choice here. We can set the window waiting timeout awfully long. In this case, the testsuite won't completely pass because of an application or test bug in the very first test. Or we can use some reasonable value and check test failures after each testsuite execution. It's up to you which way to choose. It depends on a lot of things: how big your testsuite is, how stable application design is and so on.

Note: Jemmy provides some useful APIs to find the cause for a failure. It is: org.netbeans.jemmy.util.Dumper class which dumps information about all displayed components into a file in XML format. And the org.netbeans.jemmy.util.PNGEncoder class grabs information from the screen and puts it into a PNG image file.

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo