Use Java event processing mechanism for recording and Playback

Source: Internet
Author: User


Currently, some java application GUI testing tools provide the ability to capture user operations and automatically play back user operations after the code is modified. This article analyzes the Java event processing model and its principles, introduces the key techniques to be understood for capture/playback Based on Event source recognition, and provides two implementation methods.

1. Java event Introduction

1.1 What is an event
First, let's answer the basic question "What is an event. In fact, an event itself is an abstract concept. It is an object that represents the State Changes of another object. In the object-oriented programming, event messages are the basic communication method between objects. In a graphical user interface program, GUI Component Objects generate various types of event messages based on user interaction. These event messages are captured by the event processing code of the application program, after corresponding processing, the message response object is driven to respond. When we perform a call operation on the GUI, when we click a responsive object, such as a button or menu, we will all expect an event to happen. In fact, events occur in all activities around the GUI, but the Java event processing mechanism allows you to select the events you need to handle. Events are basically the same in Java as other objects, but the difference is that events are automatically generated by the system and passed to the appropriate event handler.

1.2evolution of Java event processing
When Java developers begin to solve the problem of creating applications using Java, they realized the necessity of Java event model. This section briefly summarizes the development of Java event processing.

The event model used in jdk1.0 provides basic event processing functions. This is an inclusive model. All events are encapsulated in a single class event, and all event objects are processed by a single method handleevent. These definitions are in the component class. Therefore, only child classes of the component class can act as Event Handlers. event processing is passed to the Component Hierarchy. If the target component cannot completely process the event, the event is passed to the container of the target component.

JDK is a revolution in the programming field. It fixes some defects in the previous version and adds some important new functions such as RMI, JNI, JDBC, and JavaBean. In the event model, the basic framework is completely rewritten, and the event source is generated as an event from the java1.0 model to the delegated event model. Then, the event processing is delegated to another piece of code.

Since jdk1.2, the swing package event processing model has been introduced to provide more powerful functions, and more customizable support classes associated with GUI components. The entire event model is basically maintained in later versions, but some additional event classes and interfaces are added. The rebot class was introduced in version 1.3, which simulates mouse and keyboard events and is used for automated testing, automatic run demonstrations, and other applications requiring mouse and keyboard control.

We turn the jdk1.0 event processing model into the Java 1.0 event model, and the version event processing model after jdk1.1 is called the Java 2 event processing model.

2. Java 2 event processing model
In the java1.0 event processing model, event processing is performed as follows. Deliverevent () is used to determine the event target, which is the component or container that processes the event. This process starts from the most external and inwards of the GUI layer. When you press a button, if an event triggered by the button is detected, the button accesses its deliverevent () method, which is completed by the system. Once the target component is identified and the correct event type is sent to the postevent () method of the component, the method sends the event to the handleevent () method in sequence and waits for the return value of the method. "True" indicates that the event is fully handled. "false" means that the postevent () method will contact the target container to complete event processing.

The following is an example:

  import java.applet.*;  import java.awt.*;    public class Button1Applet extends Applet{    public void init(){add(new Button("Red"));add(new Button("Blue"));}public boolean action(Enent evt,Object whatAction){    if( !( evt.target  instanceof  Button))return false;String buttonlabel=(String)whatAction;if(buttonlabel=="Red")setBackground(Color.red);if(buttonlabel==" Blue")setBackground(Color.blue);repaint();return true;}}

When processing events in Java2, The dispatchevent ()-postevent ()-handleevent () method is not used. The Listener class is used, and each event class has an associated listener interface. The transfer of an event from the event source to the listener is performed by calling the Java method of the target listener object.

A specific Java method is defined for the occurrence of each specific event. These methods are centrally defined in the event listener interface, which inherits java. util. eventlistener. The class that implements some or all of the methods of the event listener interface is the event listener. With the occurrence of an event, the corresponding State is usually encapsulated in the event state object, which must inherit from Java. util. eventobject. The event status object is passed as a single parameter to the listener method responding to the event. The identifier of the event source that generates a specific event is: follow the prescribed design format to define the registration method for the event listener and accept references to the instance of the specified event listener interface. Sometimes, when the event listener cannot directly implement the event listener interface, or there are other additional actions, it is necessary to insert an event adapter class instance between one source and one or more listeners, to establish the relationship between them.

Let's take a look at the following simple example:

import javax.swing.*;import java.awt.*;import java.awt.event.*;public class SimpleExample extends JFrame {  JButton jButton1 = new JButton();  public SimpleExample() {    try {      jbInit();    }    catch(Exception e) {      e.printStackTrace();    }  }  public static void main(String[] args) {    SimpleExample simpleExample = new SimpleExample();  }  private void jbInit() throws Exception {    jButton1.setText("jButton1");    jButton1.addActionListener(new SimpleExample_jButton1_actionAdapter(this));    jButton1.addActionListener(new SimpleExample_jButton1_actionAdapter(this));    this.getContentPane().add(jButton1, BorderLayout.CENTER);this.setVisible(true);  }  void jButton1_actionPerformed(ActionEvent e) {    System.exit(0);  }}class SimpleExample_jButton1_actionAdapter implements java.awt.event.ActionListener {  SimpleExample adaptee;  SimpleExample_jButton1_actionAdapter(SimpleExample adaptee) {    this.adaptee = adaptee;  }  public void actionPerformed(ActionEvent e) {    adaptee.jButton1_actionPerformed(e);  }}

3. Event capture and Playback

3.1 Java event Lifecycle
Java events have the same lifecycle as everything else, and will survive. 3.1 provides the Java event lifecycle,


Events are initially generated by the event source. The event source can be a GUI Component Java Bean or an object capable of generating events. In the case of GUI components, the event source or the same body of the component (for the Abstract Window Toolkit [AWT] GUI component) or the component itself (for the swing component ). After an event is generated, it is placed in the system event queue. Now the event is under the control of the event distribution thread. The event is waiting for processing in the queue, and then the event is selected from the event queue and sent to the dispatchevent () method. The dispatchevent () method calls the processevent () method and passes a reference of the event to processevent () method. At this moment, the system will check whether there is a location for sending events. If there is no registered listener corresponding to this event type, or if no component is activated to receive event types, the event is discarded. Of course, the lifecycle of the subclass of the awtevent class is displayed. The dispatchevent () method and the processevent () method take awtevent as a parameter. But yes, javax. swing. the event is not a subclass of awtevent, but directly inherited from eventobject. The object that generates these events also defines the fireevent () method, this method sends events to any listener of the type included in the object listener list.

3.2 Java event capture
From the above analysis, we know that before any event is generated to the dispatchevent () method distribution method, all events are stored in the system event queue, and all events are stored by dispatchevent () method. Therefore, you only need to be able to reload the dispatchevent () method to obtain all system events, including user input events. Generally, the operation of the system event queue can be controlled by users. It automatically completes the task in the background. You can use the eventqueue class to view or even manipulate the system event queue.

Java provides the eventqueue class to access and even manipulate system event queues. The eventqueue class encapsulates various operations on the system event queue. In addition to the dispatchevent () method, the most critical of these operations is the push () method, the specified eventqueue can be used to replace the current eventqueue. You only need to derive a new class from the eventqueue class, and then use the push () method to replace the current eventqueue class with the derived class. In this way, all system events are forwarded to the derived eventqueue class. Then, you can overload the dispatchevent () method in the derived class to intercept all system events, including user input events. The following code provides an instance for manipulating eventqueue:

import java.awt.*;import java.awt.event.*;public class GenerateEventQueue extends Frame implements ActionListener{  Button button1 = new Button();  TextField textField1 = new TextField();  public GenerateEventQueue() {    try {      jbInit();    }    catch(Exception e) {      e.printStackTrace();    }  }  public static void main(String[] args) {    GenerateEventQueue generateEventQueue = new GenerateEventQueue();  }  private void jbInit() throws Exception {    button1.setLabel("button1");    button1.addActionListener(this) ;    textField1.setText("textField1");    this.add(button1, BorderLayout.SOUTH);    this.add(textField1, BorderLayout.CENTER);    EventQueue eq=getToolkit().getSystemEventQueue() ;    eq.postEvent(new ActionEvent(button1,ActionEvent.ACTION_PERFORMED,"test" )) ;    addWindowListener(new WinListener());    setBounds(100,100,300,200);    setVisible(true);  }  public void actionPerformed(ActionEvent e) {    textField1.setText("event is :"+e.getActionCommand()) ;  }}class WinListener extends WindowAdapter{  public void windowClosing(WindowEvent we){    System.exit(0) ;  }}

Shows the running result:


In the text field, "event is: Test" is first displayed, because the actionevent that the eventqueue object is sent to the system event queue is processed first.

The following code illustrates how to capture events:

Import Java. AWT. eventqueue; import Java. AWT. *; import Java. util. *; public class myqueueevent extends eventqueue {// defines the eventqueue subclass public myqueueevent () {} public static void main (string [] ARGs) {simpleexample. main (New String [] {null}); myqueueevent myqueueevent1 = new myqueueevent (); toolkit. getdefatooltoolkit (). getsystemeventqueue (). push (myqueueevent1);} // The Public void dispatchevent (awtevent AE) {If (AE. getsource () instanceof javax. swing. jbutton) system. out. println ("My apture:" + (javax. swing. jbutton) AE. getsource ()). gettext (); super. dispatchevent (AE );}

This program can print all the events of the current application and select the events you need to save them. Of course, you also need to parse the features of the control. Add a black part of the code above to print the name of the event source control.

In addition, you can capture events by implementing the java. AWT. event. awteventlistener interface. This listener interface can receive events distributed by component or menucomponent and Their Derived classes throughout the system. awteventlisteners only passively monitors these events. To monitor system events, you must register the listener using the addawteventlistener method of toolkit in addition to implementing interfaces.

Let's look at an example:

Import Java. AWT. awtevent; import Java. AWT. frame; import Java. AWT. toolkit; import Java. AWT. window; import Java. AWT. event. awteventlistener; import Java. AWT. event. using wevent; import Java. util. arraylist; import Java. lang. ref. weakreference; public class myawteventlistener implements awteventlistener {Private Static myawteventlistener s_singleton = NULL; // ensure that this class is only initialized once public static myawteventlistener getinstance () {If (s_singleton = NULL) {s_singleton = new myawteventlistener ();} return s_singleton;} private myawteventlistener () {// pay attention to the following line of code. If this line of code does not exist, the event that cannot be received by the system. // when the following code is registered, it only requests to receive the window_event_mask event. // However, you can actually receive the event type toolkit defined in other awtevent. getdefatooltoolkit (). addawteventlistener (this, awtevent. component_event_mask);}/* This is the implementation of the Interface Method */Public void eventdispatched (final awtevent theevent) {processevent (theevent);} Private Static void processevent (final awtevent theevent) {system. out. println (theevent. getsource (); // print the event Source switch (theevent. GETID () {case when wevent. window_opened: // system. out. println (FRAME) theevent. getsource ()). gettitle (); case when wevent. window_activated: case when wevent. window_deactivated: case when wevent. window_closing: Default: Break ;}}}

3.3 Java event playback
Event playback is actually relatively simple. For example, we now record the jbutton1 Click Event playback in frame1. Take a look at the following simple program. Just click jbutton1 and print the "Click me" string on the console.

import java.awt.*;import javax.swing.*;import java.awt.event.*;public class Frame1 extends JFrame {  private JButton jButton1 = new JButton();  public Frame1() {    try {      jbInit();    }    catch(Exception e) {      e.printStackTrace();    }  }  public static void main(String[] args) {    Frame1 frame1 = new Frame1();frame1.setVisible(true) ;  }  private void jbInit() throws Exception {    jButton1.setText("jButton1");    jButton1.addActionListener(new java.awt.event.ActionListener() {      public void actionPerformed(ActionEvent e) {        jButton1_actionPerformed(e);      }    });    this.setTitle("Test");    this.getContentPane().add(jButton1, BorderLayout.CENTER);  }  void jButton1_actionPerformed(ActionEvent e) {    System.out.println("click me") ;  }}

The following is the playback program. Java is used in the following program. AWT. robot class, which is usually used to simulate system events in automated tests or program demonstrations. This class is also useful in some applications that require mouse or keyboard control, the main purpose of this class is to conveniently implement the Java GUI automated testing platform. During event playback, we also need this class to simulate system events and record operation playback. The following code provides a simple example.

Import Java. AWT. *; import javax. swing. *; import Java. AWT. event. *; public class testreplay extends thread {public static void main (string [] ARGs) {try {// start the application frame1.main (New String [] {null}) to be played back }); // wait 3 seconds after the application starts and then play back the thread. currentthread (). sleep (3000); robot robottest = new robot (); robottest. waitforidle (); // obtain the main form of the current application based on the title name. In this example, it is "test" frame jframe = getframe ("test ");; // obtain the reference of the Control Based on the name of the control to be found in the given form and form Jbutton jbtn = getbutton (jframe, "jbutton1"); // move the cursor to the position of the control, robottest. mousemove (jbtn. getlocationonscreen (). X + jbtn. getwidth ()/2, jbtn. getlocationonscreen (). Y + jbtn. getheight ()/2); // In the control location, generate the robottest event with the mouse click. mousepress (inputevent. button#mask); robottest. mouserelease (inputevent. button#mask);} catch (exception ee) {ee. printstacktrace () ;}}// obtain the frame Private Static frame getframe (string Title) {frame [] jframes = (frame []) jframe. getframes (); For (INT I = 0; I <jframes. length; I ++) {If (jframes [I]. gettitle (). equalsignorecase (title) return jframes [I];} return NULL;} // obtain a Private Static jbutton getbutton (frame JF, string text) control named jbutton1 in a frame) {/* pay attention to the following line of code. Because the instance is relatively simple, only contentpane is a container-type control. If there are multiple container controls in jframe //, recursive processing is required, search all controls */component [] coms = (jframe) jf ). getcontentpan E (). getcomponents (); For (INT I = 0; I <coms. length; I ++) {If (! (COMS [I] instanceof jbutton) continue; If (jbutton) coms [I]). gettext (). equalsignorecase (text) Return (jbutton) coms [I];} return NULL;} public void run (){}}

After running the program, you will find that the program is printed in the console:

The string of "Click me" indicates that the event is correctly played back.

Of course, you can also directly manipulate the system event queue to play back input events. Obtain the corresponding window reference by recording the window/component name, reconstruct the mouse/keyboard event, and then put the reconstructed event directly into the system event queue, the dispatch thread executes subsequent event dispatch tasks. You also need to solve the key problem of how to obtain the reference according to the window name. This can still be implemented through the system event queue, because when a Java program creates/deletes a container, it will send a containerevent event to the system event queue, which contains references to the container. Therefore, after loading the tested program, the event replaying agent monitors the system queue and intercepts all containerevent events. If a new container is created, a reference to the new container is obtained. Because all container implements getcomponets (), you can return all components or containers contained in the container. You only need to save them to a hashmap structure and retrieve them as needed. The knowledge used in this process is actually mentioned above and in actual reference, since robot has helped us accomplish many things, there is no need to refactor a mouse or keyboard event on your own, but you can try it if you are interested.

4. Conclusion
With the development of software industry in China, software testing technology has been paid more and more attention as an important part of software quality assurance. using automated testing tools in Gui-based applications can improve the effectiveness and efficiency of software testing, in particular, regression testing can greatly reduce manpower investment and improve the reuse of test scripts. Therefore, automatic software testing platform development has become an important area of software testing. This article describes the basic but key capture and playback functions required for the development of Java-based automated testing platforms for GUI applications. All related system development is inseparable from the methods described in this article.

Trackback: http://tb.blog.csdn.net/TrackBack.aspx? Postid = 405704

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.