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...

woensdag 11 februari 2009

Flex 3 profiling without FlexBuilder Pro

Although you can't use the profiler UI from FlexBuilder if you have no professional license, you can get some profiler stuff working if you do the following:

  • find the ProfilerAgent.swf file in the .metadata\.plugins\com.adobe.flash.profiler folder of your eclipse workspace.

  • edit/create mm.cfg (to be found/created in %USERPROFILE% on win xp), and add the following line:
    PreloadSwf=\ProfilerAgent.swf?host=localhost&port=9999, where you replace the with the actual path found in the previous step.


From now on, you can start to use things from the flash.sampler library (included with FlexBuilder), and call inspection methods like getSize, startSampling etc. (see Flex help) if you start your application in debug mode...

By the way: the original post that helped me out is to be found here: http://arielsommeria.com/blog/?p=48

zondag 24 februari 2008

FlexUnit and Flex3

Since Flex3, some basic actionscript logic has changed which prevents the FlexUnit framework 0.85 (as it is available on Google Code) to find the test methods automatically. This is caused by the fact that since flex 3, for each does no longer iterate over the methods in an object.
I fixed the problem by creating an own TestCase class, which subclasses from the original one. In here, we override the getTestMethodNames function to work with DescribeType instead of for each.
This is also done in as3mock.

Here is what it looks like:


public override function getTestMethodNames():Array
{
var methodNames:Array = new Array();
var typeDesc:XML = describeType(this);
var item:XML;
for each (item in typeDesc.elements("method")){
var att:XML;
for each (att in item.attribute("name")){
var name:String = att.toXMLString();
if (0 ==name.indexOf("test")){
methodNames.push(name);
}
}
}
return methodNames;
}