donderdag 26 maart 2009

Testing flash eventListeners

In a previous project, we had a lot of trouble in testing eventListeners: we used the asynchronous test features of flexunit, but that made the code very hard to read, and slow to execute. As an example: how do you know that an event hasn’t been fired? The only way to do that is through some reasonably timeout, but that comes with a price. Another thing is you have start using inline functions, which again obfuscates the code even more.
So how are we going to test then, if we’re not going to use asynchronous functions?
Let’s split the problem in two: validating if the object responds as wished to incoming events, and firing an event.
Let’s start with the last one:

Testing if an event has been fired by your application


The trick here is to use good coding practices on your object: since event dispatching is not the core functionality of your class anyway, you’re class should delegate this to a helper. Instead of extending your object from EventDispatcher or implementing IEventDispatcher, you should pass this IEventDispatcher from outside the code, whether through the constructor, or through some setter. That way, you can pass a test double (stub/fake/mock) as IEventDispatcher to the class, and so you can test if it has been called correctly with using asynchronous code.
However, there is a small caveat: upon receiving the Event, the target and currentTarget are no longer referring to your class, but to the IEventDispatcher you sent. If this is unwished behavior, there are two things you can do: create a subclass of Event that allows you to pass in the target, or create your own EventDispatcher that delegates its calls back to the original object that implement IEventDispatcher in some way or another.

package {
import flash.events.Event;
import flash.events.IEventDispatcher;
public class ClassThatDispatchesEvents {
private var eventDispatcher:IEventDispatcher;
public function ClassThatDispatchesEvents(eventDispatcher:IEventDispatcher) {
....
this.eventDispatcher = eventDispatcher;
}

....
eventDispatcher.dispatchEvent(new Event("test"));
....

}
}

Testing if your class responds to an incoming event


Again, the trick here is delegation: instead of subscribing your class yourself to the events, again pass an IEventDispatcher to the constructor. Instead of adding the eventListeners directly to you class, add them to the IEventDispatcher instead. In the test double (stub/fake/mock) implementation of the eventDispatcher, you have access to the the function that was subscribed to the event , and it can be called synchronously. Et voila, your listeners are tested synchronously, while it’s still possible to have them declared as private. I'm also planning to publish a helper class for this purpose somewhere...