I've had the great privilege of immersing myself almost completely in Flex 3 and PureMVC these past few weeks. I'm familiar with ActionScript 3 because of my work with JavaScript and a few months ago I read the exceptionally fun book Actionscript 3.0 Animation: Making Things Move! I can't recommend that book enough if you want to learn how to develop programatic animations for fun or profit. Actually, I think the material in that book would make for a great high school trigonometry course, but I digress.
I think it was Fran Lukesh who found PureMVC while searching for an MVC solution. The deciding factor for us to use PureMVC over Cairngorm was its language independence. At andCulture we code both Flex and Flash apps so it's a distinct advantage to use the same framework in both environments to keep things consistent.
By far the most impressive feature of PureMVC is the documentation. Probably not what you were expecting, but it's true. I've never before used a project—proprietary or open source—that had comprehensive documentation like the PureMVC Implementation Idioms and Best Practices document. It's the type of documentation you read to get started learning it's ins and outs then come back to re-read 6 months later and find you've learned even more the second pass.
I recently picked up a copy of the Flex 3 Cookbook and it opened my eyes to what Flex is capable of. There are tons of great code samples throughout the book, but the one section that especially caught my attention was on FlexUnit. I feel like an idiot because I still haven't got into unit testing even though the entire Internet has long since jumped on that bandwagon and left me in the dust. Since I'm already learning a completely new language and MVC framework, I needed to take the plunge and make unit testing part of the learning process.
The examples below assume you have PureMVC and FlexUnit all setup, configured, and have a basic understanding of both. PureMVC takes a while to get used to, but FlexUnit is pretty simple and straight forward.
The FlexUnit TestCase class provides the addAsync() factory method used to attach event handlers to EventDispatchers in
order to test asynchronous events. Instead of passing just a handler to addEventListener(), using addAsync() lets FlexUnit
know how long to wait for the event to be dispatched before it's declared a failure.
dispatcher.addEventListener(eventName, addAsync(callback, 1000));
Pretty simple stuff. Definitely not rocket surgery by any means.
It only took a minute writing my first few Proxy tests before I hit a wall. Proxies send Notifications; they don't dispatch events. How are my unit tests supposed to listen for named Notifications instead of events? A few Google searches didn't clear anything up, either. I don't think unit testing has quite reached “mainstream” status yet in the ActionScript world let alone strange people like me who want to unit test PureMVC apps.
And so the PureMVC FlexUnit Testing project was born. The idea is this:
addAsync() and wait for an event to be
fired with the same name as the Notification we're concerned with.Here's what that process looks like in code form.
public function registerObserver(view:IView, proxy:IProxy, notificationName:String,
callback:Function, timeout:int):void {
// Create the hacky EventDispatcher used to throw PureMVCNotificationEvents.
var hackyDispatcher:EventDispatcher = new EventDispatcher();
// Listen for the notification event on the hacky dispather. The event type
// will be equal to the notification name.
hackyDispatcher.addEventListener(notificationName, addAsync(callback, timeout));
// Handler listening for the proxy to dispatch the specified notification.
var handler:Function = function(notification:INotification):void {
// Notification received so dispatch a new PureMVCNotificationEvent giving
// it the received INotification object.
hackyDispatcher.dispatchEvent(new PureMVCNotificationEvent(notification));
};
// Manually register an observer on this proxy for the specified notification.
view.registerObserver(notificationName, new Observer(handler, this)); }
The hackDispatcher dispatches a custom event called PureMVCNotificationEvent (link to the source—it's super simple)
passing it the observed Notification. PureMVCNotificationEvent's job is to set the event name to the name of the
Notification and provide an accessor for event handlers to get to the Notification data.
I created the PureMVCTestCase class which extends FlexUnit's TestCase and dumped registerObserver() there. When creating a
new test case, simply extend from PureMVCTestCase.
The concept is so simple, I'm sure that either someone already did this or I'm completely overlooking the blindingly obvious. Save money's on the latter.
Here's what a very simple test method in a PureMVCTestCase looks like:
private function get proxy():UserProxy {
return ApplicationFacade.getInstance(PureMVCDemo.NAME)
.retrieveProxy(UserProxy.NAME) as UserProxy;
}
private function get view():IView {
return View.getInstance(PureMVCDemo.NAME);
}
public function testListUsers():void {
// Call handleListUsersResponse when LIST_USERS_RESPONSE is sent.
registerObserver(this.view, this.proxy, UserProxy.LIST_USERS_RESPONSE,
handleListUsersResponse, 1000);
// Call a proxy method that will eventually trigger LIST_USERS_RESPONSE.
this.proxy.listUsers();
}
private function handleListUsersSuccess(e:PureMVCNotificationEvent):void {
// An array of users is sent along with the LIST_USERS_RESPONSE Notification.
// Pull it out and run some tests against it.
var users:ArrayCollection = e.notification.getBody() as ArrayCollection;
assertNotNull("Users returned are null", users);
assertTrue("No users returned.", users.length > 0);
}
I created a very basic example project you can run to see how it works first hand.
So check out the project, poke it, break it, and give some feedback. I'd love for this project to become obsolete either because PureMVC or FlexUnit integrate this logic into their projects or someone slaps me around and shows me something I'm overlooking.
The PureMVC FlexUnit Testing project is open sourced with the permission of andCulture under the BSD License.
Hooray for spam! I thought I was clever implementing some hot bot-slaying JavaScript, but turns out they weren't as stupid as I originally thought. Well done, bots.
I'm disabling commenting yet again until I devise my next strategy.
The name's Larry Marburger. I'm just some guy on the internet who likes technology — JavaScript, Rails, Flex and .NET to name a few. I use these technologies to build kickass thingamajigs at andCulture.