As you might have known there is a new version of FlexUnit in development on the opensource site at Adobe http://opensource.adobe.com/wiki/display/flexunit/FlexUnit for a few months now. This is a new breed between FlexUnit 1 and Fluint. Before delving into the asynchronous topic i would like to mention some improvements to the framework:
1. You are not any more required to explicitly extend TestSuite and TestCase classes. For the suite you just mark it as being a suite by placing [Suite] metadata tag. All test case classes that you want the suite to run should then be added as public properties in this class. The TestCase class does not require having methods that begin with “test”. Instead you mark the test methods by [Test] metadata.
2. The runner is externalized, requiring FlexUnit4UIRunner.swc for default runner. You specify the runner which a suite used by placing [RunWith] metadata tag, default runner looking like [RunWith("org.flexunit.runners.Suite")]. This being the case you can always create a custom runner and add new capabilities/functionalities in test runs.
3. Flash Builder 4 has a built in mechanism for testing, allowing one to choose what suites or test cases to run and display results in FlexUnit Results view. I wouldn’t recommend this approach right now as it has some huge memory issues which eventually will get the builder to a halt.
For a big picture about new capabilities of FlexUnit 4 go to http://opensource.adobe.com/wiki/display/flexunit/FlexUnit+4+feature+overview
Now on the asynchronous area, which has been a lot improved since the addition of Fluint. To mark a method as being part of an async process, you just add “async” under [Test] metadata [Test(async)]. This will let you access the asynchronous capabilities of the framework. The one that we’ll exemplify is usage of a RemoteObject call.
First we build the basic test class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package { import mx.rpc.remoting.RemoteObject; public class TestRemoteObject { //------------------------------------------------------------ // // Properties // //------------------------------------------------------------ /** * Service to be used in testing async calls. * @private */ private static var service:RemoteObject; //------------------------------------------------------------ // // Methods // //------------------------------------------------------------ [BeforeClass] public static function setUp():void { service = new RemoteObject(); service.endpoint = "yourEndpointHere"; } } } |
A simple declaration of the RemoteObject and a [BeforeClass] marked method. What [BeforeClass] states is that the method is called only once before the whole class is executed in the test queue. We just setup the RemoteObject with any valid endpoint. The next and final step of the test case is actually testing a method of the service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [Test(async)] public function testMyMethod():void { var token:AsyncToken = service.myMethod(); token.addResponder( Async.asyncResponder( this, new TestResponder( verifyResult, verifyFault ), 2000 ); } protected function verifyResult( e:ResultEvent, token:AsyncToken ):void { Assert.assertTrue( "Result is what i want it to be", e.result is ArrayCollection ); } protected function verifyFault( e:FaultEvent, token:AsyncToken ):void { Assert.fail( "Unintended fault from service" ); } |
Taking it from the in out, we define a TestResponder which is nothing else than a simple Responder, only that it adds an extra parameter “passThroughData” (more on this in a later post) to the result and fault methods. This responder is then added into the async capabilities of the framework using Async.asyncResponder, registering the test case (this – first param), responder (which we just built) and the timeout for call failure. On the verifyResult method you can assert everything you want from the result object and under verifyFault, if this fault is not intentional, you can just Assert.fail, telling the framework that the call failed.
Another goodie about the asynchronous testing in FlexUnit 4 is that you’re no longer needed to chain multiple async methods with events and listeners. You can accomplish this by using “order” param under [Test] metadata. So for the first async method tested you would have [Test(async,order=1)], for the second one [Test(async,order=2)] and so on. The framework will route them handy async one after another.
Next step would be to build the suite class, which as described above should look very simple:
1 2 3 4 5 6 7 8 9 10 11 | package { [Suite] [RunWith("org.flexunit.runners.Suite")] public class TestSuite { public var testRO:TestRemoteObject; } } |
And the final step is getting everything to work under an Application. The one that does that is FlexUnitCore, which as the name states is the core component coupling the suite and test cases with the runner:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:flexUnitUIRunner="http://www.adobe.com/2009/flexUnitUIRunner" creationComplete="creationCompleteHandler( event )"> <fx:Script> <![CDATA[ import mx.events.FlexEvent; import org.flexunit.runner.FlexUnitCore; protected function creationCompleteHandler( event:FlexEvent ):void { var core:FlexUnitCore = new FlexUnitCore(); core.addListener( runner ); core.run( TestSuite ); } ]]> </fx:Script> <flexUnitUIRunner:TestRunnerBase id="runner" width="100%" height="100%"/> </s:Application> |
The runner, being externalized, is added into the works using core.addListener, thus receiving events from core regarding the tests. Simply call core.run() on the suite and hope that green checks are everywhere. To view the detailed code for async capabilities in FlexUnit go to http://opensource.adobe.com/svn/opensource/flexunit/branches/4.x/FlexUnit4/src/org/flexunit/async/.
Download example source code from here


No comments yet.
Leave a comment