JavaAn Automated Test Program using the Java Robot Class

An Automated Test Program using the Java Robot Class

Java Programming Notes # 1474


Preface

Programming in Java doesn’t have to be dull and boring.  In fact,
it’s possible to have a lot of fun while programming in Java.  This
is the second lesson in a short miniseries that shows you how to use the
Robot class to write programs that are both fun and useful.

New features in SDK Version 1.3

One of the new features that was released in SDK Version 1.3 was the Robot
class.  According to Sun,

“This class is used to generate native system input events for the
purposes of test automation, self-running demos, and other applications
where control of the mouse and keyboard is needed. The primary purpose of
Robot is to facilitate automated testing of Java platform implementations.”

What is a Java robot?

The Robot class makes it possible for your Java program to temporarily
take control of the mouse and keyboard input functionality at the operating-system
level.

Several instance methods are available

The Robot class provides several instance methods, (including
the following),
by which your program can produce mouse and keyboard
input, just as though that input were being provided by a human user.

  • mouseMove – Moves the mouse pointer to a set of specified absolute
    screen coordinates given in pixels.
  • mousePress – Presses one of the buttons on the mouse.
  • mouseRelease – Releases one of the buttons on the mouse.
  • keyPress – Presses a specified key on the keyboard.
  • keyRelease – Releases specified key on the keyboard.

A word of caution

A runaway Java Robot object has the ability to wrest control away
from the human user, so you need to be a little careful.  For example,
if you allow your Java Robot program to go into an infinite loop,
making mouse moves, clicking the mouse, and entering keystrokes, you may
find that the only practical way to regain control of your computer is to
either turn off the power or press the reset button to force your computer
to restart.

Three lessons in the miniseries

According to my current plans, this miniseries on the Robot class
will consist of three lessons.  The first lesson, entitled Introduction
to the Java Robot Class in Java
, demonstrated the low-level nature of
an object of the Robot class.  That was accomplished by showing
you how to create a Java robot that can manipulate other non-Java programs,
such as Windows Notepad and Internet Explorer.

This lesson, which is the second lesson in the miniseries, will show you
how to use a robot to perform automatic testing on a Java GUI.

The third lesson will show you how to write a robot program to provide
a visual animated demonstration of the use of a Java GUI.

Viewing tip

You may find it useful to open another copy of this lesson in a separate
browser window.  That will make it easier for you to scroll back and
forth among the different listings and figures while you are reading about
them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection
of online Java tutorials.  You will find those lessons published at Gamelan.com.  However,
as of the date of this writing, Gamelan doesn’t maintain a consolidated index
of my Java tutorial lessons, and sometimes they are difficult to locate there. 
You will find a consolidated index at www.DickBaldwin.com.

Preview

I will discuss the sample programs named Robot02 and Robot02Slave
in this lesson.

(The program named Robot02 uses a Robot object to
perform tests on an instance of the class named Robot02Slave.)

The sample programs in this lesson will show you how to use a Java robot
to perform automatic testing on a Java GUI.

Discussion
and Sample Code

Description of the program named Robot02Slave

Figure 1 shows the GUI produced by the program named Robot02Slave
on startup, before being exercised by the Robot object belonging
to the program named Robot02.  The GUI contains eight JToggleButton
objects and one JTextField object in a GridLayout.

Figure 1 Test program GUI on startup

As you can see, the JToggleButton in the upper left corner has
the focus and none of the toggle buttons are selected at startup.

Can be manipulated by Robot02

The class named Robot02Slave is used to instantiate a GUI object
that can be manipulated by an object of the class named Robot02
The class can also be used to instantiate a GUI object that can be manipulated
manually using the mouse and the keyboard, independent of the robot object.

Will fire action and focus events

When you click on any of the buttons, the button will fire an ActionEvent
Also, when you click on any of the buttons, the button will gain the focus
and fire a FocusEvent if the button didn’t already have the focus.

Button will toggle between two states

Because the button is a JToggleButton, it will also toggle between
being selected and not being selected.  When the button is not selected,
it is colored a light shade of gray, and appears to protrude from the screen
(due to the Motif look and feel). When the button is selected, it
is colored a dark shade of gray and appears to be pushed into the screen
(see Figure 2 later for an example of selected buttons).

Text field also fires action and focus events

When you click the text field, it will gain the focus.  When you
press the ENTER key while the text field has the focus, it will fire an
ActionEvent

Focus traversal

If you successively press the focus traversal key, the focus will
traverse the components using the focus traversal policy that is
in effect.  I did not implement a new focus traversal policy, nor did
I change the focus traversal key.  Therefore, the default focus traversal
policy and the default focus traversal key are both in effect.  Successively
pressing the TAB key will cause the focus to move from one component to the
next, top to bottom, left to right, and then back to the top left.

If you hold down the SHIFT key and successively press the TAB key, the
focus will traverse the components in the reverse direction.

Focus events

In all cases that the focus moves from one component to another, regardless
of the cause, the component that gains the focus and the component that
loses the focus will each fire a FocusEvent.

Common event handlers

A common ActionEvent handler is registered on each of the eight
buttons and the text field.  The event handler gets and displays the
value of the actionCommand property for the component that fired
the event.

Whenever a component loses or gains the focus, that component will fire
a FocusEvent.  A common FocusEvent handler is registered
on each of the eight buttons and the text field.  The event handler
gets and displays the value of the name property for the component
that fired the event, along with an indication as to whether the focus was
lost or gained by that component.

Sample screen outputs

Here is the screen output produced by the event handlers as a result
of manually clicking the button with the H while the button with the A has
the focus.

A lost focus H gained focus
ActionCommand = H

(Note that the value of the name property for each button
was set to match the text on the face of the button.  The text on the
face of a button is the default action command for the button.  Also
note that the value of the name property for the text field was set
to I.)

Here is the screen output produced by pressing the TAB key several times
in succession, causing the focus to traverse the components in a forward
direction.

H lost focus I gained focus
I lost focus A gained focus
A lost focus B gained focus
B lost focus C gained focus
C lost focus D gained focus
D lost focus E gained focus
E lost focus F gained focus

Note that the button showing the H had the focus when this sequence began.

Nothing special was required

With one exception, nothing special was done to cause this program to
be suitable for manipulation by the program named Robot02
That exception has to do with the main methodAs you
will see later, the main method does not include any code that is
necessary for this program to behave properly.  The code in the main
method simply instantiates an object of the controlling class.

The program was tested using SDK 1.4.1 under WinXP.

The main method for the program named Robot02Slave

I will discuss this program in fragments.  A complete listing of
the program is shown in Listing 24 near the end of the lesson.

Most of the code in this program is straightforward, and is explained
in other tutorial lessons on my web
site
.  Therefore, the discussion of this program will be very brief. 
The more detailed discussion will be reserved for the program named Robot02
later in the lesson.

The program named Robot02Slave begins in Listing 1 where the main
method starts by instantiating an object of the class to which it belongs.
 

public class Robot02Slave extends JFrame
implements ActionListener,FocusListener{

public static void main(String[] args){
new Robot02Slave();
}//end main

Listing 1

This main method can be used to run the program in a standalone mode independent
of the robot program.

(Note than this class implements two listener interfaces.  Therefore,
an object of this class is a valid listener for action events and focus
events.)

Prepare the JFrame for use

The constructor for the class begins in Listing 2.  The code in Listing
2 prepares the JFrame for use by setting the title, layout, location on
the screen, size, etc.
 

  public Robot02Slave(){//constructor

setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
getContentPane().setLayout(
new GridLayout(3,3));
setBounds(10,10,250,200);
setTitle("Copyright 2003, R.G.Baldwin");

Listing 2

Create the button objects

The code in Listing 3 instantiates eight anonymous JToggleButton
objects and adds them to the content pane.
 

    for(int cnt = 0; cnt < 8; cnt++){
getContentPane().add(new JToggleButton(
"" + (char)('A' + cnt)));
}//end for loop

Listing 3

The text on the faces of the buttons is set to the letters A through H.

Add a text field

The code in Listing 4 adds a JTextField object as the ninth component.
 

    getContentPane().add(new JTextField(""));

Listing 4

Get a list of the components

The code in Listing 5 gets a list of references to all nine components
and stores them in the elements of an array of references of type Component.

    Component[] components =
getContentPane().getComponents();

Listing 5

Register event listeners on the components

The code in Listing 6 registers action and focus listeners on each of
the components.
 

    for(int cnt = 0; cnt < components.length;
cnt++){
//Must downcast in order to register an
// action listener.
if(components[cnt] instanceof
JToggleButton){
((JToggleButton)components[cnt]).
addActionListener(this);
}else if(components[cnt] instanceof
JTextField){
((JTextField)components[cnt]).
addActionListener(this);
}//end else

//Register a focus listener on each
// component
components[cnt].addFocusListener(this);

//Give each component a name. Make the
// name match the text on the face of the
// buttons. Name the text field "I"
components[cnt].setName(
"" + (char)('A' + cnt));
}//end for loop

Listing 6

In addition, the code in Listing 6 sets the value of the name property
of each component to a unique value by which we can recognize it later.

The code in Listing 6 is straightforward, so I won’t discuss it further.

Set the look and feel, and make the GUI visible

The code in Listing 7 sets the look and feel to Sun’s Motif, and makes
the GUI visible.
 

    String plafClassName =
"com.sun.java.swing.plaf.motif." +
"MotifLookAndFeel";
try{
UIManager.setLookAndFeel(plafClassName);
}catch(Exception ex){ex.printStackTrace();}

//Cause the new L&F to be applied
SwingUtilities.updateComponentTreeUI(this);

//Make the frame visible
setVisible( true );
}//end constructor

Listing 7

Once again, the code in Listing 7 is straightforward, so I won’t discuss
it further.

Listing 7 signals the end of the constructor.

Define the action listener

Because the class named Robot02Slave implements the ActionListener
interface, it must define the method named actionPerformed, which
is declared in the interface.  This is accomplished in Listing 8.
 

  public void actionPerformed(ActionEvent e){
System.out.println("ActionCommand = " +
e.getActionCommand());
}//end actionPerformed

Listing 8

This code makes it possible to register this object as an action
listener on each of the components in Listing 6.

Display the actionCommand property

The code in the actionPerformed method gets and displays the
actionCommand
property belonging to the component that fired the ActionEvent
The default value for the actionCommand property for a JToggleButton
object is the text on the face of the button.  The value of the actionCommand
property for a JTextField object is the contents of the text field
when the event was fired.

Define the focus listener

Because the class named Robot02Slave implements the FocusListener
interface, it must define the methods named focusLost, and focusGained,
which are declared in the interface.  This is accomplished in Listing
9.
 

  public void focusLost(FocusEvent e){
System.out.print(e.getComponent().getName()
+ " lost focus ");
}//end focus lost

public void focusGained(FocusEvent e){
System.out.println(e.getComponent().getName()
+ " gained focus");
}//end focusGained

}//end class definition

Listing 9

As is the case with the action listener, this code makes it possible to
register this object as a focus listener on each of the components
in Listing 6.

Firing focus events

Whenever the focus moves from one component to another, the component
losing the focus and the component gaining the focus each fire a focus event.

Among other things, the FocusEvent object passed to the focusLost
method identifies the component that lost the focus.  The FocusEvent
object passed to the focusGained method identifies the component
that gained the focus.

Display the value of the name property

When a focus event is fired, the code in Listing 9 displays the value
of the name property belonging to the component that either lost or
gained the focus, causing it to fire the event.

End of Robot02Slave program

Listing 9 also signals the end of the program named Robot02Slave.

Description of the program named Robot02

There is no GUI for the program named Robot02.  The program
simply starts, instantiates an object of the Robot02Slave class,
executes a series of mouse moves, mouse clicks, and keyboard inputs on that
object, and then terminates.

A dynamic process

Because this is a dynamic process, you will need to actually run the program
to see exactly how it behaves.  Figure 2 shows the GUI produced by
the program named Robot02Slave after being exercised by the Robot
object belonging to the program named Robot02.

Figure 2 Test program GUI after being exercised by the
robot

You may find it useful to compare the appearance of the GUI in Figure
2 with the appearance of the GUI at startup shown earlier in Figure 1.

Behavior of the program named Robot02

This program illustrates the use of the Robot class, which was
released in SDK Version 1.3, to exercise the various features of a Java
GUI.

The program instantiates an object of the class named Robot02Slave
The GUI belonging to this object contains eight JToggleButton objects
and a JTextField object in a GridLayout as shown in Figures
1 and 2.  This program uses an object of the Robot class to
exercise the GUI belonging to the Robot02Slave object.

Focus traversal

The upper-left button in the GUI shown in Figure 1 holds the focus when
the program starts.

The robot presses the TAB key a sufficient number of times to cause the
focus to traverse all of the components once in the forward direction according
to the focus traversal policy in effect.  Because the default focus
traversal policy is in effect, this causes the focus to move from left to
right, top to bottom, ending on the text field in the bottom right as shown
in Figure 2.

Then the robot holds down the SHIFT key and presses the TAB key a sufficient
number of times to cause the focus to traverse all of the components once
in the reverse direction.  At this point, the button in the upper left
once again holds the focus, as shown in Figure 1.

A time delay is inserted between successive presses of the TAB key so
that you can view the focus as it traverses the components.

Click the mouse on each button

The program identifies each of the components in the GUI produced by Robot02Slave,
and determines the physical location of each of those components on the
screen.

Once the robot has determined the location of a component, it presses
and then releases the left mouse button on that component.  This constitutes
a click on the button.

How do the components behave?

Clicking the mouse on a JToggleButton object causes the button
to fire an ActionEvent and a FocusEvent.

Clicking the mouse on a JTextField object causes the text field
to fire a FocusEvent.

Enter text into the JTextField object

Then, the program determines if the component being processed is a JTextField
object.  If so, it types the text Done into the text field and
presses the ENTER key to cause the text field to fire an ActionEvent.

This program was tested on my machine using SDK 1.4.1 under WinXP

Will discuss in fragments

As usual, I will discuss this program in fragments.  A complete listing
of the program is shown in Listing 23 near the end of the lesson. 
The class definition begins in Listing 10 with the declaration of a reference
variable to hold a reference to an object of type Robot.

public class Robot02{
Robot robot;

Listing 10

Create an object to be exercised

The code in Listing 11 instantiates a new object of the class named
Robot02Slave
, discussed earlier in this lesson.  That object’s reference
is saved in a reference variable named slave, in order that it can
be manipulated by the robot.

  Robot02Slave slave = new Robot02Slave();

Listing 11

Create some keycodes

The code in Listing 12 creates an array object of type int, and
initializes the elements of the array to contain the virtual keycodes for
the characters done.

(Note that regardless of the case of the characters in the names
of the virtual keycodes, these keycodes must be combined with the virtual
SHIFT keycode to produce upper-case versions of the characters.)

  int keyInput[] = {
KeyEvent.VK_D,
KeyEvent.VK_O,
KeyEvent.VK_N,
KeyEvent.VK_E
};//end keyInput array

Listing 12

As shown earlier in Figure 2, these characters will be automatically entered
into the JTextField object belonging to the GUI being exercised by
the robot.

The main method

The main method for the program named Robot02 is shown in
Listing 13.
 

  public static void main(String args[]){
System.out.println("Start test program");
new Robot02();
System.out.println("nEnd test program");
}//end main

Listing 13

As you can see, the code in the main method simply displays starting
and ending messages and instantiates an object of the Robot02 class.

The constructor

The behavior of the program is controlled by code in the constructor,
(which begins in Listing 14), and code in a method that is called
by code in the constructor.

  public Robot02(){//constructor
try{
robot = new Robot();
}catch(AWTException e){
e.printStackTrace();
}//end catch

Listing 14

The constructor begins by instantiating an object of the Robot
class, and saving that object’s reference in the instance variable named
robot, which was declared in Listing 10.  Because the reference
is saved in an instance variable, it is accessible throughout the class.

Is the slave object visible?

Because of delays involved in displaying graphics, it is possible that
the robot could become ready to be manipulate the GUI before the GUI is
ready to be manipulated.  Therefore, the code in Listing 15 loops until
the showing property of the GUI object becomes true.
 

    while(!(slave.isShowing())){
//loop until slave is showing on the screen
}//end while loop

Listing 15

(In order to avoid tying up computer resources with a tight loop,
and slowing things down even more, it might be better to cause the current
thread to sleep for a short period of time during each iteration of the
loop in Listing 15.)

Get a list of GUI components

The code in Listing 16 gets a list of the components belonging to the
GUI and saves the references to those components in the elements of an array
object of type Component.
 

    Component[] components =
slave.getContentPane().getComponents();

Listing 16

The length of the array will be used by the robot to determine
how many times to press the TAB key to cause the focus to traverse all of
the components in the GUI.

The references stored in the array will be used by the robot later to
click the mouse on each of the components.

Traverse the components in the forward direction

The code in Listing 17 prints a message, and then presses the TAB key
a sufficient number of times to cause the focus to traverse all of the components
once in the forward direction.
 

    System.out.println("nTraverse forward");
for(int cnt = 0;
cnt < (components.length - 1); cnt++){
robot.keyPress(KeyEvent.VK_TAB);
//Insert delays to cause the focus to
// traverse the components slowly.
robot.delay(1000);
}//end for loop

Listing 17

A one-second delay is inserted between each key press to make it possible
to view the focus as it traverses the components.

Focus events

Because focus events are fired each time the focus moves from one component
to the next, the code in Listing 17 produces the following output on the
screen.

Traverse forward
A lost focus B gained focus
B lost focus C gained focus
C lost focus D gained focus
D lost focus E gained focus
E lost focus F gained focus
F lost focus G gained focus
G lost focus H gained focus
H lost focus I gained focus

Each line of text shown above (except for the first line) was actually
the result of two focus events being fired.  One event was fired by
the component that lost the focus.  The other event was fired by the
component that gained the focus.

(If you review the event handler methods in Listing 9, you will see
that I invoked the print method for focusLost and the println
method for focusGained.  This causes each pair of events to
produce a single line of text in the output.)

Where is the screen output produced?

It is important for you to understand that except for the first line
of text shown above, the screen output that is produced when the focus moves
is being produced by the event handler methods belonging to the GUI object,
and is not being produced by the robot.  The robot simply causes the
focus to move by pressing the TAB key.  The behavior that results is
strictly dependent on the event handlers belonging to the GUI being manipulated.

Traverse the components in the reverse direction

The code in Listing 18 prints a message and then presses the SHIFT key.
 

    System.out.println("nTraverse backwards");
//Press the shift key.
robot.keyPress(KeyEvent.VK_SHIFT);
for(int cnt = 0;
cnt < (components.length - 1); cnt++){
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(1000);
}//end for loop
//Release the shift key.
robot.keyRelease(KeyEvent.VK_SHIFT);

Listing 18

Then the robot presses the TAB key a sufficient number of times to cause
the focus to traverse all of the components once in the reverse direction. 
Then the robot releases the SHIFT key.

Focus events

Again, because focus events are fired each time the focus moves from one
component to the next, the code in Listing 18 produces the following output
on the screen.

Traverse backwards
I lost focus H gained focus
H lost focus G gained focus
G lost focus F gained focus
F lost focus E gained focus
E lost focus D gained focus
D lost focus C gained focus
C lost focus B gained focus
B lost focus A gained focus

Click the components and enter text into the
text field

The robot’s next task is to execute a mouse click on each of the components
and to enter text into the JTextField object.  This process
begins in Listing 19, which shows the beginning of a for loop that
is used to execute this process.
 

    System.out.println("nClick all components");
for(int cnt = 0; cnt < components.length;
cnt++){
Point location =
components[cnt].getLocationOnScreen();
System.out.print("Click at: " +
location.x + ", " + location.y + " ");

Listing 19

Get and save screen location for each component

As shown in Listing 19, the first task in the for loop is to get,
save, and display the actual screen coordinates for each component.

(Note that these are absolute coordinates in pixels relative to the
upper-left corner of the screen, and are not coordinates relative to the
upper-left corner of the object containing the components.)

Partial screen output

The code in Listing 19 produced the following screen output during the
first iteration of the for loop.

Click all components
Click at: 14, 33

The first line of text shown above was produced by the first statement
in Listing 19, which is outside the for loop.  The second line
of text shown above shows the absolute screen coordinates of the upper left-hand
corner of the component whose reference is stored in the first element of
the array object referred to by the reference variable named components.

(The setBounds method invoked by the GUI constructor in Listing
2 causes the upper-left corner of the GUI to be located at screen coordinates
10, 10.  The above output indicates that the upper-left corner of the
component is four pixels to the right of and 23 pixels below the upper-left
corner of the JFrame object that is the container for the GUI. 
Compare that with Figure 1 to confirm those numbers in your own mind.)

Execute a mouse click on the component

The code in Listing 20 invokes the mouseMoveAndClick method to
execute a mouse click on the physical location on the screen where the component
resides.
 

      mouseMoveAndClick(location.x,location.y);

Listing 20

The mouseMoveAndClick method

At this point, I am going to set the for loop in the constructor
aside momentarily and discuss the method named mouseMoveAndClick,
as shown in its entirety in Listing 21.

  public void mouseMoveAndClick(
int xLoc, int yLoc){
robot.mouseMove( xLoc,yLoc );
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);

robot.delay(1000);
}//end mouseMoveAndClick

Listing 21

The code in Listing 21 causes the robot to move the mouse pointer to a
screen location specified by the incoming parameters.

Then the robot presses and releases the left mouse button, which represents
a mouse click on that screen location.

Events may be fired

If a JToggleButton object, which does not already have the focus,
is located at those coordinates, the combination of the operating system
and the Java virtual machine working together causes the button at that
location to gain the focus and to fire both an ActionEvent and a
FocusEvent(If the button already has the focus, it won’t
fire the FocusEvent.)

If a JTextField object, which does not already have the focus,
is located at those coordinates, the combination of the operating system
and the Java virtual machine causes the text field to gain the focus and
to fire a FocusEvent(If the text field already has the
focus, it won’t fire the FocusEvent.)

(Recall that if one component loses the focus when another component
gains the focus, the component losing the focus will also fire a FocusEvent.)

A one-second delay

The code in Listing 21 also inserts a one-second delay to make it possible
to view the effect of clicking the button.

Enter text into the text field

Returning to the discussion of the for loop in the constructor,
the code in Listing 22 tests to see if the component being processed during
the current iteration of the for loop is a JTextField object.

      if(components[cnt] instanceof JTextField
&& components[cnt].hasFocus()){
System.out.println("nEnter text");
robot.keyPress(KeyEvent.VK_SHIFT);
for (int cnt2 = 0;
cnt2 < keyInput.length; cnt2++){
if(cnt2 > 0){
robot.keyRelease(KeyEvent.VK_SHIFT);
}//end if
robot.keyPress(keyInput[cnt2]);
robot.delay(1000);
}//end for loop
//Cause the text field to fire an
// ActionEvent
robot.keyPress(KeyEvent.VK_ENTER);
}//end if
}//end for loop
}//end constructor

Listing 22

Execute key presses to enter text and fire ActionEvent

If the component is a JTextField object, and if it has the focus,
the code in Listing 22 causes the robot to type the text Done into
the text field as shown in Figure 2.

(Note the use of the virtual SHIFT key to cause the first character
to be entered in upper case and the remaining characters to be entered in
lower case.  Also note the use of the virtual ENTER key to cause the
text field to fire an ActionEvent after all the characters have been
typed into the text field.)

The screen output

The code in Listings 19 through 22 causes the following screen output.

Click all components
Click at: 14, 33 ActionCommand = A
Click at: 94, 33 A lost focus B gained focus
ActionCommand = B
Click at: 174, 33 B lost focus C gained focus
ActionCommand = C
Click at: 14, 90 C lost focus D gained focus
ActionCommand = D
Click at: 94, 90 D lost focus E gained focus
ActionCommand = E
Click at: 174, 90 E lost focus F gained focus
ActionCommand = F
Click at: 14, 147 F lost focus G gained focus
ActionCommand = G
Click at: 94, 147 G lost focus H gained focus
ActionCommand = H
Click at: 174, 147 H lost focus I gained focus

Enter text
ActionCommand = Done

The screen output is mixed

The screen output shown above is a mixture of output produced by the
Robot02
program and output produced by the event handlers belonging to
the GUI object being manipulated by the robot.  The coordinate information
is displayed by the robot.  The information regarding action events
and focus events is produced by the event handlers belonging to the GUI.

The end of the Robot02 program

And that is the end of the code for the program named Robot02.

Run the Program

I encourage you to copy the code from Listings 23 and 24 into your text
editor, compile it, and execute it.  Experiment with it, making changes,
and observing the results of your changes.

The Robot class was first released in SDK Version 1.3, so you
will need to be running Version 1.3 or later.  This program was tested
on my machine using SDK 1.4.1 under WinXP

Summary

In this lesson, I have taught you how to use a Java robot to perform
automatic testing on a Java GUI.

What’s Next?

The next lesson in this miniseries will show you how to write an animated
robot program to provide an animated visual demonstration of the use of
a Java GUI.

Complete Program Listings


Complete listings of the programs discussed in this lesson are shown in
Listings 23 and 24 below.
 

/*File Robot02.java
Copyright 2003 R.G.Baldwin

Illustrates the use of the java.awt.Robot class,
which was released in SDK Version 1.3.

The program instantiates an object of the class
named Robot02Slave. This object contains eight
JToggleButton objects and a JTextField object
in a GridLayout.

The program begins with the upper-left button
holding the focus.

The program presses the tab key eight times in
succession to cause the focus to traverse all of
the components in the forward direction according
to the default focus traversal policy, which
moves the focus from top left to bottom right.

At this point, the text field in the bottom right
holds the focus.

Then the program holds down the shift key and
presses the tab key eight more times in
succession to cause the focus to traverse all of
the components in the reverse direction.

At this point, the button in the upper left
holds the focus.

The program identifies each of the components
in the GUI produced by Robot02Slave. It
determines the physical location of each of those
components on the screen. Once it has determined
the location of a component, it presses the left
mouse button on that component and then releases
the left mouse button on that component. If the
component is a button, this causes the button to
fire an ActionEvent along with a FocusEvent.

If the component is a text field, it simply fires
a FocusEvent when clicked by the mouse.

Then, the program determines if the component is
a JTextField object. If so, it enters the text
"Done" into the text field and presses the Enter
key to cause the text field to fire an
ActionEvent.

Tested using SDK 1.4.1 under WinXP
************************************************/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Robot02{
//Create a robot object that will be used to
// exercise a GUI object.
Robot robot;

//The following GUI object will be exercised by
// the robot.
Robot02Slave slave = new Robot02Slave();

//The following text will be entered into the
// text field on the GUI.
int keyInput[] = {
KeyEvent.VK_D,
KeyEvent.VK_O,
KeyEvent.VK_N,
KeyEvent.VK_E
};//end keyInput array
//-------------------------------------------//

public static void main(String args[]){
System.out.println("Start test program");
new Robot02();
System.out.println("nEnd test program");
}//end main
//-------------------------------------------//

public Robot02(){//constructor
try{
robot = new Robot();
}catch(AWTException e){
e.printStackTrace();
}//end catch

//Make certain that the slave is visible on
// the screen.
while(!(slave.isShowing())){
//loop until slave is showing on the screen
}//end while loop

//Get a list of the components on the slave
Component[] components =
slave.getContentPane().getComponents();

//Traverse the focus path from the beginning
// to the end in the forward direction.
System.out.println("nTraverse forward");
for(int cnt = 0;
cnt < (components.length - 1); cnt++){
robot.keyPress(KeyEvent.VK_TAB);
//Insert delays to cause the focus to
// traverse the components slowly.
robot.delay(1000);
}//end for loop

//Traverse the focus path from the end to the
// beginning in the reverse direction.
System.out.println("nTraverse backwards");
//Press the shift key.
robot.keyPress(KeyEvent.VK_SHIFT);
for(int cnt = 0;
cnt < (components.length - 1); cnt++){
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(1000);
}//end for loop
//Release the shift key.
robot.keyRelease(KeyEvent.VK_SHIFT);

//Automatically click each button on the
// slave GUI. Then enter text into the text
// field
System.out.println("nClick all components");
for(int cnt = 0; cnt < components.length;
cnt++){
//Get, save, and display actual screen
// location of a component
Point location =
components[cnt].getLocationOnScreen();
System.out.print("Click at: " +
location.x + ", " + location.y + " ");

//Execute a mouse click on the physical
// location on the screen where the
// component resides.
mouseMoveAndClick(location.x,location.y);

//If the component is a JTextField object,
// execute keystrokes that will enter the
// word "Done" into the text field. Note
// the use of upper and lower case.
if(components[cnt] instanceof JTextField
&& components[cnt].hasFocus()){
System.out.println("nEnter text");
robot.keyPress(KeyEvent.VK_SHIFT);
for (int cnt2 = 0;
cnt2 < keyInput.length; cnt2++){
if(cnt2 > 0){
robot.keyRelease(KeyEvent.VK_SHIFT);
}//end if
robot.keyPress(keyInput[cnt2]);
robot.delay(1000);
}//end for loop
//Cause the text field to fire an
// ActionEvent
robot.keyPress(KeyEvent.VK_ENTER);
}//end if
}//end for loop
}//end constructor
//-------------------------------------------//

public void mouseMoveAndClick(
int xLoc, int yLoc){
robot.mouseMove( xLoc,yLoc );
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);

robot.delay(1000);
}//end mouseMoveAndClick

}//end class Robot02

Listing 23

 

/*File Robot02Slave.java
Copyright 2003 R.G.Baldwin

Illustrates the use of the java.awt.Robot class,
which was released in SDK Version 1.3.

This program is used to instantiate a GUI object
that is manipulated by an object of the class
named Robot02. The program can also be used to
instantiate a GUI object that can be manipulated
manually using the mouse and the keyboard,
independent of the robot object.

An object of this class contains eight
JToggleButton objects and a JTextField object
in a GridLayout.

When you click on any of the buttons with the
mouse, the button fires an ActionEvent. Because
it is a JToggleButton, it also changes between
a light shade of gray and a dark shade of gray.
When you enter text into the text field, the text
field fires an ActionEvent.

The same ActionEvent handler is registered on all
eight buttons and the text field. The event
handler gets and displays the ActionCommand for
the component that fires the event.

Whenever any of the components lose or gain the
focus, they fire a FocusEvent. The same
FocusEvent handler is registered on all eight
buttons and the text field. The event handler
gets and displays the name of the component along
with an indication as to whether the focus was
lost or gained.

Tested using SDK 1.4.1 under WinXP
************************************************/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Robot02Slave extends JFrame
implements ActionListener,FocusListener{

//This main method can be used to run the
// program in a standalone mode independent of
// the robot.
public static void main(String[] args){
new Robot02Slave();
}//end main
//-------------------------------------------//

public Robot02Slave(){//constructor

//Prepare the JFrame for use
setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
getContentPane().setLayout(
new GridLayout(3,3));
setBounds(10,10,250,200);
setTitle("Copyright 2003, R.G.Baldwin");

//Create eight buttons and add them to the
// content pane
for(int cnt = 0; cnt < 8; cnt++){
getContentPane().add(new JToggleButton(
"" + (char)('A' + cnt)));
}//end for loop

//Add a text field as the ninth component
getContentPane().add(new JTextField(""));

//Get a list of the components
Component[] components =
getContentPane().getComponents();

//Register listeners on each component and
// give each component a name
for(int cnt = 0; cnt < components.length;
cnt++){
//Must downcast in order to register an
// action listener.
if(components[cnt] instanceof
JToggleButton){
((JToggleButton)components[cnt]).
addActionListener(this);
}else if(components[cnt] instanceof
JTextField){
((JTextField)components[cnt]).
addActionListener(this);
}//end else

//Register a focus listener on each
// component
components[cnt].addFocusListener(this);

//Give each component a name. Make the
// name match the text on the face of the
// buttons. Name the text field "I"
components[cnt].setName(
"" + (char)('A' + cnt));
}//end for loop

//Set the look and feel to Motif
String plafClassName =
"com.sun.java.swing.plaf.motif." +
"MotifLookAndFeel";
try{
UIManager.setLookAndFeel(plafClassName);
}catch(Exception ex){ex.printStackTrace();}

//Cause the new L&F to be applied
SwingUtilities.updateComponentTreeUI(this);

//Make the frame visible
setVisible( true );
}//end constructor
//-------------------------------------------//

//Define the ActionEvent handler that is
// registered on each of the components.
public void actionPerformed(ActionEvent e){
System.out.println("ActionCommand = " +
e.getActionCommand());
}//end actionPerformed
//-------------------------------------------//

//Define the FocusEvent handlers that are
// registered on each of the components.
public void focusLost(FocusEvent e){
System.out.print(e.getComponent().getName()
+ " lost focus ");
}//end focus lost

public void focusGained(FocusEvent e){
System.out.println(e.getComponent().getName()
+ " gained focus");
}//end focusGained

}//end class definition

Listing 24

Copyright 2003, Richard G. Baldwin.  Reproduction in whole or in part
in any form or medium without express written permission from Richard Baldwin
is prohibited.

About the author

Richard Baldwin is
a college professor (at Austin Community College in Austin, TX) and private
consultant whose primary focus is a combination of Java, C#, and XML. In
addition to the many platform and/or language independent benefits of Java
and C# applications, he believes that a combination of Java, C#, and XML
will become the primary driving force in the delivery of structured information
on the Web.

Richard has participated in numerous consulting projects, and he frequently
provides onsite training at the high-tech companies located in and around
Austin, Texas.  He is the author of Baldwin’s Programming Tutorials, which has gained a worldwide
following among experienced and aspiring programmers. He has also published
articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology to
real-world problems.

Baldwin@DickBaldwin.com

-end-
 

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories