Thursday, February 18, 2010

Can FlexUnit4 test Parsley applications?

One of the challenges you face when adopting a dependency injection framework for Flex development is how to test classes that use features of the DI framework. For example when you use the Parsley framework a Command class is typically implemented as follows:-

Here the command dispatches a CommandCompleteEvent message when the service returns a result using Parsley's MessageDispatcher. If you want to test this implementation you need to be able to write a test class that can handle Parsley's CommandCompleteEvent message. You'd probably write the test class like this:-

and you'd probably run it in the normal way as follows:-

Sadly since the test class is not in the Parsley context the [MessageDispatcher] and [MessageHandler] decorators are ignored, the test will never run the command and the test will always fail. Additionally you probably want to be able to [Inject] the test classes dependencies rather than instantiating them programatically in the setUp method. Clearly for this work the test class needs to be a "managed" object (i.e. an object in the Parsley context). It's easy to put the test class into the context but getting FlexUnit4 to use the managed object is easier said than done. What we really need is a Parsley-aware test "runner" (like Spring Java's context-based test runner) that you could use as follows:-

but unfortunately at the time of writing there's no such Parsley test runner.

If you declare the test class in a Parsley ApplicationContext.mxml and instantiate it using Parsley's FlexContextBuilder, the Parsley [MessageDispatcher], [MessageHandler] and [Inject] decorators will work but the challenge is to get FlexUnit4 to use the "managed" instance of the test class. Unfortunately the way FlexUnit4 works at the moment you specify the class names of the test classes to FlexUnit4 and FlexUnit4 goes off and creates its own instances of the test classes. Major disconnect.

If you take a look under the hood of FlexUnit4 you'll find that the parameters to FlexUnitCore's run method can be instances as well as classes. So you might expect the following to work:-

but don't try that at home because this undocumented feature of FlexUnit4 isn't fully implemented yet and it doesn't work. That's a shame since this would make FlexUnit4 much easier to use with dependency injection frameworks.

Time to give up? The good news is that Parsley 2.2 includes support for generic "short-lived" objects (originally included to support the command pattern) that we can leverage to insert the test class into the Parsley context programatically with createDynamicContext().addObject(this). The following works:-

I guess one day we might have test runner support in Parsley and Spring ActionScript. Until then I guess we have to make do with these workarounds.


Brian said...

FWIW - Writing a test runner is pretty dirt simple for FU4. I've written one for mock-as3 and mockolate with relative ease.

If you can make a call which will wire up an existing instance using Parsely, then you could easily have the runner auto-wire your test. I know Swiz has this featuere, so I'm sure it's in Parsely. Check out the runner for mock-as3 @ for an example.

ben.clinkinbeard said...

Swiz works perfectly fine with FlexUnit 4. Just sayin'.

sang said...

what version of parsley and flexunit are you using?
I'm trying to follow your example and I am getting error from parsley..

Graeme Harker said...

Parsley 2.2 and FlexUnit 4

Darren Bishop said...

If anyone's interested in better Parsley integration...
FlexUnit4 Testing with Parsley

Simon Gladman said...

Graeme, that's been a great help, many thanks.

Hope you are well, haven't seen you for ages.