Verify events with EventCatcher

Một phần của tài liệu Manning JUnit recipes practical methods for program (Trang 605 - 608)

Problem

You want a simple way to verify the events that an Observable generates.

Background

Verifying that an Observable generates the expected events is not a difficult task, but when programming Swing applications in particular, event sources are every- where. It is easy to fall into the trap of duplicating test code throughout your applica- tion, when instead you ought to create a single object that knows how to listen for events and verify them against the events you expect to receive. In short: you could write your own Spy listener, but why not leverage good work already done by others?

Recipe

GSBase provides the utility class EventCatcher which you can attach to any object.

It is a universal event listener that collects every event it “hears” and provides access to those events as a List. Your typical test scenario will be the following, using a GUI widget as an example:

1 Create the GUI widget whose behavior you want to verify.

2 Create an EventCatcher and tell it to listen to the GUI widget.

3 Make the widget do something interesting.

4 Iterate over the list of events caught by the EventCatcher and verify each one—or even just the ones of interest.

Of course, the GUI widget could really be any event source, but because Mike orig- inally wrote EventCatcher to use on Swing applications, it was written specifically with that context in mind.

Table 15.1 Other recipes in this book that feature GSBase

Recipe GSBase feature

2.1—Test your equals method EqualsTester

2.9—Let collections compare themselves BaseTestCase.assertCollectionsEqual() 4.5—Scan the file system for tests

4.6—Separate the different kinds of test suites RecursiveTestSuite, TestFilter 4.7—Control the order of some of your tests OrderedTestSuite

575 Verify events with EventCatcher

Listing 15.1 shows an example of using EventCatcher to verify receiving the HierarchyEvent that a Swing component produces when the component hierar- chy changes—that is, when one component is added to the content pane of another. To test more complex scenarios, you only need to make more assertions about the events which you expect your Swing components to generate.

package junit.cookbook.gsbase.test;

import java.awt.event.HierarchyEvent;

import javax.swing.JFrame;

import javax.swing.JOptionPane;

import junit.framework.TestCase;

import com.gargoylesoftware.base.testing.EventCatcher;

public class ConfirmationDialogTest extends TestCase { public void testEvents() throws Exception { JOptionPane optionPane =

new JOptionPane(

"Are you sure?!",

JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION);

EventCatcher eventCatcher = new EventCatcher();

eventCatcher.listenTo(optionPane);

JFrame mainFrame = new JFrame("The Main Frame");

mainFrame.getContentPane().add(optionPane); B

assertEquals(1, eventCatcher.getEventCount());

Object eventAsObject = eventCatcher.getEventAt(0);

assertTrue(eventAsObject instanceof HierarchyEvent); C

} }

Generates a HierarchyEvent—Adding a Swing component to another component gen- erates a HierarchyEvent, indicating that the hierarchy of components has changed.

Cannot try assertEquals()—Most Swing events do not implement equals() the way a Value Object should, so there is little point in trying to compare an expected HierarchyEvent with the one that Swing generated.

Listing 15.1 Using EventCatcher on a Swing component

B C

576 CHAPTER 15 GSBase

Discussion

Although Mike Bowler originally built EventCatcher to help him test Swing com- ponents, it is useful to help with any event listener design. The EventCatcher is a universal event listener, relying on time-honored naming conventions to discover the events an object might generate at runtime. This means that as long as your event source adheres to the usual Java naming conventions for the event listener implementation pattern, you can use EventCatcher to help verify the behavior of any event source.

When you invoke EventCatcher.listenTo(), the event catcher scans the meth- ods on the event source you specify, looking for the types of events it might gener- ate. Specifically, the EventCatcher searches for methods whose names start with add and end with Listener, and which take exactly one argument, assuming that such a method signals a type of event the object might generate. The Event- Catcher then invokes addEventListener() for each Event, registering itself with the event source as an EventListener.1

When the event source generates an event, it notifies its listeners by invoking a method on them. The EventCatcher’s dynamic invocation handler intercepts this method invocation and remembers the event so that you can ask for it later. How does EventCatcher know that these method invocations are event notifications?

Once again, conventions to the rescue. An event notification is typically imple- mented as a method invocation with one parameter: the event; therefore, Event- Catcher assumes that the first parameter to any method invocation is an EventObject. Also, because it is uncommon to invoke any method on an event lis- tener other than the event notification method, it is quite safe to assume that any method invocation is an event notification.

NOTE Sometimes it’s not an event notification—By default, EventCatcher handles equals() and hashCode() differently, as you might have other tests that invoke those methods. Any other method invocation is assumed to be an event notification. If this fails for you, then subclass EventCatcher and aug- ment the dynamic invocation handler to handle any other special cases you might have. As of press time, the method getListener() returns a listener for a given event type. Override that method to substitute your specialized invocation handler for the one that EventCatcher creates by default.

Finally, we noted above that most event objects do not implement equals() in a manner consistent with a Value Object. That means that we are typically unable to

1 Here, Event is any subclass of java.util.EventObject, such as AWTEvent or PropertyChangedEvent.

577 Test serialization

compare an expected event object with the actual event object using the equals() method. EventCatcher provides the next best thing. The method assertEvents- AppearEquals() accepts a List of expected event objects and compares them with the EventCatcher’s internal List using a simple, clever algorithm. Two event objects “appear” to be equal if they come from the same class and if their corre- sponding JavaBean properties have the same values. For a more thorough discus- sion of the notion of “appears equal,” see recipe 15.4.

Certainly, the EventCatcher provides a wealth of features for testing compo- nents that use the event/listener design, something rampant in the Swing UI framework.

Related

■ 15.4—Compare JavaBeans using “appears equal”

Một phần của tài liệu Manning JUnit recipes practical methods for program (Trang 605 - 608)

Tải bản đầy đủ (PDF)

(753 trang)