Home >
We don’t need to be jealous of Java developers anymore. The new version of FlexUnit 4 just got closer in similarity to the JUnit (http://www.junit.org/) project and supports many of the features JUnit has, and more! FlexUnit4 combines features from the previous FlexUnit 1.0 features and Fluint (http://code.google.com/p/fluint/).
The FlexUnit team did a splendid job here. Kudos to the FlexUnit team and particularly to my friends over at Digital Primates: Michael Labriola’s and Jeff Tapper’s. Check out their blog entries and presentation here:
http://blogs.digitalprimates.net/codeSlinger/index.cfm/2009/5/3/FlexUnit-4-in-360-seconds
http://blogs.digitalprimates.net/jefftapper/index.cfm/2009/5/20/FlexUnit-4-feature-overview
On May 18, 2009, the project moved into the beta phase: http://opensource.adobe.com/wiki/display/flexunit/FlexUnit+4+feature+overview
Additionally, it appears that FlexUnit 4 will be supported, to some extent, by Flex Builder ooops I mean Flash Builder 4 (sorry, I am still having a hard time adjusting to the new name!), however, it seems that the plugin class code generated in FB will still support FlexUnit 1 style and not FlexUnit 4.
Help support the project by voting to include FlexUnit 4 in Flash Builder 4 here: http://bugs.adobe.com/jira/browse/FB-18873
I encourage you to download the FlexUnit 4 beta 1 (Turnkey Test Project). The project includes many of the possible tests you can create.
http://opensource.adobe.com/wiki/display/flexunit/Downloads
Here are some of the main features:
1. Easier to create test suite and test cases classes
2. You create test runner easier as well as integrate runners from other frameworks
3. Better usage with continuous integration due to automation integration
4. Better handling of Asynchronous tests
5. Better handling of exceptions
6. Framework is Metadata driven
7. Allows User interface testing
8. Ability to create test sequences
Creating Test Suite and Test Case
We will start off by creating Test Suite and Test Case. To get started let’s create a new project. Select File -> New -> New Flex Project. Call the project FlexUnit4. Copy the following SWCs into the project libs folder:
FlexUnit1Lib.swc, FlexUnit4.swc, FlexUnit4UIRunner.swc, hamcrest-as3.swc

Test Suite
In FlexUnit 4 your test suite and test case classes don’t need to inherit from the TestSuite super class anymore. There is also no need to call for a specific Test and Suite classes as we did in FlexUnit 1. Take a look at a basic Test Suite.
Note that we are using the Suite metadata, which indicates that the class is a Suite. The RunWith tag is used FlexUnit 4. FlexUnit 4 is a collection of runners that will run to create a complete set of tests. You can define each runner to implement a specific interface. For instance, you can select to use the class you reference to run the tests in that class instead of the default runner built into FlexUnit4.
What it means is that the framework is flexible enough to support future runners and allow developers to create their own runners, but still use the same UI. In fact, currently there are runners that exist for FlexUnit 1, FlexUnit 4, Fluint and SLT.
Test Case class
The test case, just as the test suite, doesn’t have to inherit from the TestCase anymore and got simplified. The class is based on metadata and although we spoke about RunWith and Suite metadata tags, I would like to introduce you to some more metadata tags available before creating the test case.
• [Suite] - indicates that the class is a Suite
• [Test] - Test metadata replace the test prefixed in front of each method. Support the expected, async, order, timeout and ui attributes.
• [RunWith] - Used to select the runner to be used
• [Ignore] - Instead of commenting out a method you can just place the ignore metadata
• [Before] - Replaces the setup() method in FlexUnit 1 and allow using multiple methods. Supports async, timeout, order and ui attributes.
• [After] - Replaces the teardown() method in FlexUnit 1 and allow using multiple methods. Supports async, timeout, order and ui attributes
• [BeforeClass] - allow running methods before test class. Supports order attribute.
• [AfterClass] - allow running methods after test class. Supports order attribute.
Take a look at a complete example of a test case class using FlexUnit 4:
Assertion methods
Each test class is based on class we will be testing, therefore it is helpful to create an instance of the class we will be testing so we can have it handy. Our example here is simple and we aren't really doing a real test of a class.
The Before and After metadata tags indicates that these methods will run before and after each test method.
The Test metadata replaces the prefix in front of each method so here we have a method that doesn’t start with test. Notice that unlike the previous version of FlexUnit you have to indicate the class to assert since our class doesn’t inherit from TestCase anymore.
In FlexUnit 1 we used to comment out the code to ignore a method that we don’t want to test any more. The Ignore metadata tag allows skipping a method.
Note: In case you want to create a stack order for the tests or the before after methods, you can just add the order attribute, like this: [Test(order=1)]
Exception handling
The test metadata allows defining an exception attribute and makes it possible to test exceptions. The way it works is that the test method with the expected attributes points to the error message you expect and the test will pass when the exception is raised.
Let’s take a look at the example below. The rangeTest method creates a new Sprite object and tries to get the children at index 0 which exists so we will not get an error message and the test will fail. To get a success method, change the child.getChildAt(1); Since child at index 1 doesn’t exist, the exception will be raised and the test will pass:
Another example is expecting an assertion error. Take a look at the testAssertNullNotEqualsNull method. The method is expecting AssertionFailedError fail error. The assertEquals method will succeed since null equals null so the test will fail. Change the statement to the following:
And you will get the test to succeed.
Test runners
The test runner is similar to FlexUnit1 test runner.
We create an instance of the FlexUnitCore. FlexUnitCore extends EventDispatcher and acts as the facade for running the tests. It mimics the JUnitCore in methods and functionality. See: http://junit.sourceforge.net/javadoc_40/org/junit/runner/JUnitCore.html.
Once the creationCompleteHandler handler is called we can add the UIListener listener
We have the option to set listener to the UI. What’s happening is that the FlexUnitCore class has async listener watcher, which waits until all listeners are completed before it begins the runner execution.
The next line calls the run method to start executing the tests. The run method accepts ...args so you will be able to list all the suites you want the runner to run
We also need an instance of the TestRunnerBase component.
Hamcrest assertion method
In addition to the new standard assertions such as Assert.assertEquals or Assert.assertFalse, FlexUnit 4 supports new methods thanks to Hamcrest (http://github.com/drewbourne/hamcrest-as3/tree/master). Hamcrest is a library that is based on the idea of matchers. Each matcher can be set to match conditions for your assertions.
Create a new test case and call it FlexUnitCheckRangeTester.
FlexUnit4HamcrestSuite class includes the FlexUnitCheckRangeTester class.
Lastly, don’t forget to include the new test suite in FlexUnit4.mxml:
Asynchronous Tests
In case you worked with FlexUnit 1 in the past, you know that it isn’t always easy to create asynchronous tests and test event driven code. I often found myself modifying existing classes just to accommodate FlexUnit or creating tests in “hackish” way. One of Fluint's biggest advantages is the ability to accommodate multiple asynchronous events. FlexUnit 4 incorporated Fluint functionality and it supports enhanced asynchronous and includes asynchronous setup and teardown. This feature is possible by every test including the overhead of the asynchronous script.
Create a new Test Case and call it TestAsynchronous
Adjust the test FlexUnit4Suite.as
Theories
FlexUnit 4 introduces a whole new concept called theories. A Theory as the name suggests allows you to create a test to check your assumptions in regard to how a test should behave. This type of test is useful when you have a method you would like to test which can have large or even infinite sets of values. The test takes parameters (data points) and these data points can be used in conjunction with the test.
Create a new Test Suite and call it FlexUnit4TheorySuite.
Add the test suite to the FlexUnit4.mxml:
flexUnitCore.run( FlexUnit4Suite, FlexUnit4HamcrestSuite, FlexUnit4TheorySuite );
Testing User Interfaces
There is a tool called FlexMonkey (http://code.google.com/p/flexmonkey/) to test both the application visual appearance as well as the visual behavior.
Up until FlexUnit 4 we didn’t have the ability to test user interfaces and MXML components weren’t an option when creating unit testing.
FlexUnit 4 includes the concept of sequence so you can create sequences that includes all the operations you would like to perform on a UI.
This is a few pages from the first draft of the "Advanced Flex 4" book coming out this year, click here to learn more.
Please keep in mind that this is not a final version and the pages weren't tech reviewed or proofed yet.
The FlexUnit team did a splendid job here. Kudos to the FlexUnit team and particularly to my friends over at Digital Primates: Michael Labriola’s and Jeff Tapper’s. Check out their blog entries and presentation here:
http://blogs.digitalprimates.net/codeSlinger/index.cfm/2009/5/3/FlexUnit-4-in-360-seconds
http://blogs.digitalprimates.net/jefftapper/index.cfm/2009/5/20/FlexUnit-4-feature-overview
On May 18, 2009, the project moved into the beta phase: http://opensource.adobe.com/wiki/display/flexunit/FlexUnit+4+feature+overview
Additionally, it appears that FlexUnit 4 will be supported, to some extent, by Flex Builder ooops I mean Flash Builder 4 (sorry, I am still having a hard time adjusting to the new name!), however, it seems that the plugin class code generated in FB will still support FlexUnit 1 style and not FlexUnit 4.
Help support the project by voting to include FlexUnit 4 in Flash Builder 4 here: http://bugs.adobe.com/jira/browse/FB-18873
I encourage you to download the FlexUnit 4 beta 1 (Turnkey Test Project). The project includes many of the possible tests you can create.
http://opensource.adobe.com/wiki/display/flexunit/Downloads
Here are some of the main features:
1. Easier to create test suite and test cases classes
2. You create test runner easier as well as integrate runners from other frameworks
3. Better usage with continuous integration due to automation integration
4. Better handling of Asynchronous tests
5. Better handling of exceptions
6. Framework is Metadata driven
7. Allows User interface testing
8. Ability to create test sequences
Creating Test Suite and Test Case
We will start off by creating Test Suite and Test Case. To get started let’s create a new project. Select File -> New -> New Flex Project. Call the project FlexUnit4. Copy the following SWCs into the project libs folder:
FlexUnit1Lib.swc, FlexUnit4.swc, FlexUnit4UIRunner.swc, hamcrest-as3.swc

Test Suite
In FlexUnit 4 your test suite and test case classes don’t need to inherit from the TestSuite super class anymore. There is also no need to call for a specific Test and Suite classes as we did in FlexUnit 1. Take a look at a basic Test Suite.
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class FlexUnit4Suite
{
public var flexUnitTester:FlexUnitTester;
}
}
Note that we are using the Suite metadata, which indicates that the class is a Suite. The RunWith tag is used FlexUnit 4. FlexUnit 4 is a collection of runners that will run to create a complete set of tests. You can define each runner to implement a specific interface. For instance, you can select to use the class you reference to run the tests in that class instead of the default runner built into FlexUnit4.
[RunWith("org.flexunit.runners.Suite")]
[RunWith("org.flexunit.experimental.theories.Theories")]
What it means is that the framework is flexible enough to support future runners and allow developers to create their own runners, but still use the same UI. In fact, currently there are runners that exist for FlexUnit 1, FlexUnit 4, Fluint and SLT.
Test Case class
The test case, just as the test suite, doesn’t have to inherit from the TestCase anymore and got simplified. The class is based on metadata and although we spoke about RunWith and Suite metadata tags, I would like to introduce you to some more metadata tags available before creating the test case.
• [Suite] - indicates that the class is a Suite
• [Test] - Test metadata replace the test prefixed in front of each method. Support the expected, async, order, timeout and ui attributes.
• [RunWith] - Used to select the runner to be used
• [Ignore] - Instead of commenting out a method you can just place the ignore metadata
• [Before] - Replaces the setup() method in FlexUnit 1 and allow using multiple methods. Supports async, timeout, order and ui attributes.
• [After] - Replaces the teardown() method in FlexUnit 1 and allow using multiple methods. Supports async, timeout, order and ui attributes
• [BeforeClass] - allow running methods before test class. Supports order attribute.
• [AfterClass] - allow running methods after test class. Supports order attribute.
Take a look at a complete example of a test case class using FlexUnit 4:
package flexUnitTests
{
import com.elad.framework.utils.Helper;
import flash.display.Sprite;
import flexunit.framework.Assert;
public class FlexUnitTester
{
// Reference declaration for class to test
private var classToTestRef : com.elad.framework.utils.Helper;
//--------------------------------------------------------------------------
//
// Before and After
//
//--------------------------------------------------------------------------
[Before]
public function runBeforeEveryTest():void
{
// implement
}
[After]
public function runAfterEveryTest():void
{
// implement
}
//--------------------------------------------------------------------------
//
// Tests
//
//--------------------------------------------------------------------------
[Test]
public function checkMethod():void
{
Assert.assertTrue( true );
}
[Test(expected="RangeError")]
public function rangeCheck():void
{
var child:Sprite = new Sprite();
child.getChildAt(0);
}
[Test(expected="flexunit.framework.AssertionFailedError")]
public function testAssertNullNotEqualsNull():void
{
Assert.assertEquals( null, "" );
}
[Ignore("Not Ready to Run")]
[Test]
public function methodNotReadyToTest():void
{
Assert.assertFalse( true );
}
}
}
Assertion methods
Each test class is based on class we will be testing, therefore it is helpful to create an instance of the class we will be testing so we can have it handy. Our example here is simple and we aren't really doing a real test of a class.
// Reference declaration for class to test
private var classToTestRef : com.elad.framework.utils.Helper;
The Before and After metadata tags indicates that these methods will run before and after each test method.
[Before]
public function runBeforeEveryTest():void
{
// implement
}
[After]
public function runAfterEveryTest():void
{
// implement
}
The Test metadata replaces the prefix in front of each method so here we have a method that doesn’t start with test. Notice that unlike the previous version of FlexUnit you have to indicate the class to assert since our class doesn’t inherit from TestCase anymore.
[Test]
public function checkMethod():void
{
Assert.assertTrue( true );
}
In FlexUnit 1 we used to comment out the code to ignore a method that we don’t want to test any more. The Ignore metadata tag allows skipping a method.
[Ignore("Not Ready to Run")]
[Test]
public function methodNotReadyToTest():void
{
Assert.assertFalse( true );
}
Note: In case you want to create a stack order for the tests or the before after methods, you can just add the order attribute, like this: [Test(order=1)]
Exception handling
The test metadata allows defining an exception attribute and makes it possible to test exceptions. The way it works is that the test method with the expected attributes points to the error message you expect and the test will pass when the exception is raised.
Let’s take a look at the example below. The rangeTest method creates a new Sprite object and tries to get the children at index 0 which exists so we will not get an error message and the test will fail. To get a success method, change the child.getChildAt(1); Since child at index 1 doesn’t exist, the exception will be raised and the test will pass:
[Test(expected="RangeError")]
public function rangeCheck():void
{
var child:Sprite = new Sprite();
child.getChildAt(0);
}
Another example is expecting an assertion error. Take a look at the testAssertNullNotEqualsNull method. The method is expecting AssertionFailedError fail error. The assertEquals method will succeed since null equals null so the test will fail. Change the statement to the following:
Assert.assertEquals( null, “” );
And you will get the test to succeed.
[Test(expected="flexunit.framework.AssertionFailedError")]
public function testAssertNullNotEqualsNull():void
{
Assert.assertEquals( null, null );
}
Test runners
The test runner is similar to FlexUnit1 test runner.
<?xml version="1.0" encoding="utf-8"?>
<FxApplication xmlns="http://ns.adobe.com/mxml/2009"
xmlns:flexUnitUIRunner="http://www.adobe.com/2009/flexUnitUIRunner"
minWidth="1024" minHeight="768"
creationComplete="creationCompleteHandler(event)">
<Script>
<![CDATA[
import flexUnitTests.FlexUnit4TheorySuite;
import flexUnitTests.FlexUnit4HamcrestSuite;
import mx.events.FlexEvent;
import flexUnitTests.FlexUnit4Suite;
import org.flexunit.listeners.UIListener;
import org.flexunit.runner.FlexUnitCore;
// holds an instance of the <code>FlexUnitCore</code> class
private var flexUnitCore:FlexUnitCore;
protected function creationCompleteHandler(event:FlexEvent):void
{
flexUnitCore = new FlexUnitCore();
//Listener for the UI, optional
flexUnitCore.addListener( new UIListener( testRunner ));
//This run statements executes the unit tests for the FlexUnit4 framework
flexUnitCore.run( FlexUnit4Suite );
}
]]>
</Script>
<flexUnitUIRunner:TestRunnerBase id="testRunner" width="100%" height="100%" />
</FxApplication>
We create an instance of the FlexUnitCore. FlexUnitCore extends EventDispatcher and acts as the facade for running the tests. It mimics the JUnitCore in methods and functionality. See: http://junit.sourceforge.net/javadoc_40/org/junit/runner/JUnitCore.html.
private var flexUnitCore:FlexUnitCore;
Once the creationCompleteHandler handler is called we can add the UIListener listener
protected function creationCompleteHandler(event:FlexEvent):void
{
flexUnitCore = new FlexUnitCore();
We have the option to set listener to the UI. What’s happening is that the FlexUnitCore class has async listener watcher, which waits until all listeners are completed before it begins the runner execution.
//Listener for the UI, optional
flexUnitCore.addListener( new UIListener( testRunner ));
The next line calls the run method to start executing the tests. The run method accepts ...args so you will be able to list all the suites you want the runner to run
//This run statements executes the unit tests for the FlexUnit4 framework
flexUnitCore.run( FlexUnit4Suite );
}
We also need an instance of the TestRunnerBase component.
Hamcrest assertion method
In addition to the new standard assertions such as Assert.assertEquals or Assert.assertFalse, FlexUnit 4 supports new methods thanks to Hamcrest (http://github.com/drewbourne/hamcrest-as3/tree/master). Hamcrest is a library that is based on the idea of matchers. Each matcher can be set to match conditions for your assertions.
Create a new test case and call it FlexUnitCheckRangeTester.
package flexUnitTests
{
import org.hamcrest.AbstractMatcherTestCase;
import org.hamcrest.number.between;
public class FlexUnitCheckRangeTester extends AbstractMatcherTestCase
{
//--------------------------------------------------------------------------
//
// Before and After
//
//--------------------------------------------------------------------------
private var numbers:Array;
[Before]
public function runBeforeEveryTest():void
{
numbers = new Array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
}
[After]
public function runAfterEveryTest():void
{
numbers = null;
}
//--------------------------------------------------------------------------
//
// Tests
//
//--------------------------------------------------------------------------
[Test]
public function betweenRangeExclusive():void
{
assertMatches("assert inside range", between(numbers[0], numbers[10], true), 5);
assertDoesNotMatch("assert outside range", between(numbers[0], numbers[10], true), 11);
}
[Test]
public function betweenRangeInclusive():void
{
assertMatches("assert inside range", between(numbers[0], numbers[10]), 5);
assertDoesNotMatch("assert outside range", between(numbers[0], numbers[10]), 11);
}
[Test]
public function betweenReadableDescription():void
{
assertDescription("a Number between <0> and <10>", between(numbers[0], numbers[10]));
assertDescription("a Number between <0> and <10> exclusive", between(numbers[0], numbers[10], true));
}
}
}
FlexUnit4HamcrestSuite class includes the FlexUnitCheckRangeTester class.
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class FlexUnit4HamcrestSuite
{
public var flexUnitCheckRangeTester:FlexUnitCheckRangeTester;
}
}
Lastly, don’t forget to include the new test suite in FlexUnit4.mxml:
flexUnitCore.run( FlexUnit4Suite, FlexUnit4HamcrestSuite );
Asynchronous Tests
In case you worked with FlexUnit 1 in the past, you know that it isn’t always easy to create asynchronous tests and test event driven code. I often found myself modifying existing classes just to accommodate FlexUnit or creating tests in “hackish” way. One of Fluint's biggest advantages is the ability to accommodate multiple asynchronous events. FlexUnit 4 incorporated Fluint functionality and it supports enhanced asynchronous and includes asynchronous setup and teardown. This feature is possible by every test including the overhead of the asynchronous script.
Create a new Test Case and call it TestAsynchronous
package flexUnitTests
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flexunit.framework.Assert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
import org.flexunit.async.Async;
public class AsynchronousTester
{
private var service:HTTPService;
//--------------------------------------------------------------------------
//
// Before and After
//
//--------------------------------------------------------------------------
[Before]
public function runBeforeEveryTest():void
{
service = new HTTPService();
service.resultFormat = "e4x";
}
[After]
public function runAfterEveryTest():void
{
service = null;
}
//--------------------------------------------------------------------------
//
// Tests
//
//--------------------------------------------------------------------------
[Test(async,timeout="500")]
public function testServiceRequest():void
{
service.url = "../assets/file.xml";
service.addEventListener(ResultEvent.RESULT, Async.asyncHandler( this, onResult, 500 ), false, 0, true );
service.send();
}
[Test(async,timeout="500")]
public function testeFailedServicRequest():void
{
service.url = "file-that-dont-exists";
service.addEventListener( FaultEvent.FAULT, Async.asyncHandler( this, onFault, 500 ), false, 0, true );
service.send();
}
[Test(async,timeout="500")]
public function testEvent():void
{
var EVENT_TYPE:String = "eventType";
var eventDispatcher:EventDispatcher = new EventDispatcher();
eventDispatcher.addEventListener(EVENT_TYPE, Async.asyncHandler( this, handleAsyncEvnet, 500 ), false, 0, true );
eventDispatcher.dispatchEvent( new Event(EVENT_TYPE) );
}
[Test(async,timeout="500")]
public function testMultiAsync():void
{
testEvent();
testServiceRequest();
}
//--------------------------------------------------------------------------
//
// Asynchronous handlers
//
//--------------------------------------------------------------------------
private function onResult(event:ResultEvent, passThroughData:Object):void
{
Assert.assertTrue( event.hasOwnProperty("result") );
}
private function handleAsyncEvnet(event:Event, passThroughData:Object):void
{
Assert.assertEquals( event.type, "eventType" );
}
private function onFault(event:FaultEvent, passThroughData:Object):void
{
Assert.assertTrue( event.fault.hasOwnProperty("faultCode") );
}
}
}
Adjust the test FlexUnit4Suite.as
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class FlexUnit4Suite
{
public var flexUnitTester:FlexUnitTester;
public var asynchronousTester:AsynchronousTester;
}
}
Theories
FlexUnit 4 introduces a whole new concept called theories. A Theory as the name suggests allows you to create a test to check your assumptions in regard to how a test should behave. This type of test is useful when you have a method you would like to test which can have large or even infinite sets of values. The test takes parameters (data points) and these data points can be used in conjunction with the test.
Create a new Test Suite and call it FlexUnit4TheorySuite.
package flexUnitTests
{
import org.flexunit.assertThat;
import org.flexunit.assumeThat;
import org.flexunit.experimental.theories.Theories;
import org.hamcrest.number.greaterThan;
import org.hamcrest.object.instanceOf;
[Suite]
[RunWith("org.flexunit.experimental.theories.Theories")]
public class FlexUnit4TheorySuite
{
private var theory:Theories;
//--------------------------------------------------------------------------
//
// DataPoints
//
//--------------------------------------------------------------------------
[DataPoint]
public static var number:Number = 5;
//--------------------------------------------------------------------------
//
// Theories
//
//--------------------------------------------------------------------------
[Theory]
public function testNumber( number:Number ):void
{
assumeThat( number, greaterThan( 0 ) );
assertThat( number, instanceOf(Number) );
}
}
}
Add the test suite to the FlexUnit4.mxml:
flexUnitCore.run( FlexUnit4Suite, FlexUnit4HamcrestSuite, FlexUnit4TheorySuite );
Testing User Interfaces
There is a tool called FlexMonkey (http://code.google.com/p/flexmonkey/) to test both the application visual appearance as well as the visual behavior.
Up until FlexUnit 4 we didn’t have the ability to test user interfaces and MXML components weren’t an option when creating unit testing.
FlexUnit 4 includes the concept of sequence so you can create sequences that includes all the operations you would like to perform on a UI.
package flexUnitTests
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.controls.Button;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import org.flexunit.Assert;
import org.flexunit.async.Async;
import org.fluint.sequence.SequenceCaller;
import org.fluint.sequence.SequenceEventDispatcher;
import org.fluint.sequence.SequenceRunner;
import org.fluint.sequence.SequenceSetter;
import org.fluint.sequence.SequenceWaiter;
import org.fluint.uiImpersonation.UIImpersonator;
public class FlexUnit4CheckUITester
{
private var component:UIComponent;
private var btn:Button;
//--------------------------------------------------------------------------
//
// Before and After
//
//--------------------------------------------------------------------------
[Before(async,ui)]
public function setUp():void
{
component = new UIComponent();
btn = new Button();
component.addChild( btn );
btn.addEventListener( MouseEvent.CLICK, function():void { component.dispatchEvent( new Event( 'myButtonClicked' ) ); } )
Async.proceedOnEvent( this, component, FlexEvent.CREATION_COMPLETE, 500 );
UIImpersonator.addChild( component );
}
[After(async,ui)]
public function tearDown():void
{
UIImpersonator.removeChild( component );
component = null;
}
//--------------------------------------------------------------------------
//
// Tests
//
//--------------------------------------------------------------------------
[Test(async,ui)]
public function testButtonClick():void
{
Async.handleEvent( this, component, "myButtonClicked", handleButtonClickEvent, 500 );
btn.dispatchEvent( new MouseEvent( MouseEvent.CLICK, true, false ) );
}
[Test(async,ui)]
public function testButtonClickSequence():void
{
var sequence:SequenceRunner = new SequenceRunner( this );
var passThroughData:Object = new Object();
passThroughData.buttonLable = 'Click button';
with ( sequence )
{
addStep( new SequenceSetter( btn, {label:passThroughData.buttonLable} ) );
addStep( new SequenceWaiter( component, 'myButtonClicked', 500 ) );
addAssertHandler( handleButtonClickSqEvent, passThroughData );
run();
}
btn.dispatchEvent( new MouseEvent( MouseEvent.CLICK, true, false ) );
}
//--------------------------------------------------------------------------
//
// Handlers
//
//--------------------------------------------------------------------------
private function handleButtonClickEvent( event:Event, passThroughData:Object ):void
{
Assert.assertEquals( event.type, "myButtonClicked" );
}
private function handleButtonClickSqEvent( event:*, passThroughData:Object ):void
{
Assert.assertEquals(passThroughData.buttonLable, btn.label);
}
}
}
This is a few pages from the first draft of the "Advanced Flex 4" book coming out this year, click here to learn more.
Please keep in mind that this is not a final version and the pages weren't tech reviewed or proofed yet.




Facebook Application Development
This is really a great addition, and a great write-up. Discovering flunit was like a breath of fresh air after having struggled with FlexUnit for a year or better before that. It's nice to see Flex unit testing really maturing.
Elad,
The writeup is spot on, thanks for putting it up.
Saurabh Narula
This feature looks great. For more information about this and all the features of Flex 4 and Flash Builder 4, see this upcoming class by Rivello Multimedia Consulting; http://www.blog.rivello.org/?p=324
I'm not able to find how to structure a project the will have my Flex app, test and the test runner in the same Eclipse project. It seems, an Flex project in Eclipse, using Flex Builder can have only one main app. So, it's either my application or the test runner. How do I solve this problem? It seems an simple issue and people must have solved it if they use flexunit for their production development, but I'm not sure how to do it.
The range error test isn't set up correctly.
[Test(expected="RangeError")]
public function rangeCheck():void
{
var child:Sprite = new Sprite();
child.getChildAt(0);
}
Above, this will always throw an exception, as no children have been added to the sprite instance. Changing the index will have no effect.
Just add something like a button instance to the sprite.
[Test(expected="RangeError")]
public function rangeCheck():void
{
var sprite:Sprite = new Sprite();
var button:Button = new Button();
sprite.addChild(button);
sprite.getChildAt(0);
}
An exception will not be thrown when the index is 0.
Hi Patrick,
The idea of the test was to show how the metadata works.
The method will always success since it's expecting an error and that's the idea of the test that has the expected error metadata. If the test doesn't get an error it fails. Feel free to copy the code and you can see that you always get a 'green' light since it will produce an error. I am showing examples, but feel free to play around and change them :)
Cheers,
Elad Elrom
"I'm not able to find how to structure a project the will have my Flex app, test and the test runner in the same Eclipse project. "
The tests are recommended to be created in a separate folder. One can decide to do this under the src folder or in a separate souce folder added to the project. (Flash builder Project-> Properties -> Build Path -> SourcePath).
What is menat by main application. (Default applicaiton ? ) Flex Project can have only one default application, but many applications are allowed. Using executeFlexUnit tests option ( 1. (Run, Debug, Profile -> FlexUnit tests) , 2. Right click on the project explorer, 3. Short keys etc in the Flash Builder will pick up appropriate application and launch the same. ). It need not be the default application
If you have more querries regarding FlexUnit usage in FlashBuiler (beta2), please contact us at ranik@adobe.com
Thanks for the article. A must read for all flex developers who are going to use FlexUnit 4.
Hi Elad,
You mentioned that...
"Let’s take a look at the example below. The rangeTest method creates a new Sprite object and tries to get the children at index 0 which exists so we will not get an error message and the test will fail. To get a success method, change the child.getChildAt( 1 ); Since child at index 1 doesn’t exist, the exception will be raised and the test will pass:
var child:Sprite = new Sprite( );
child.getChildAt( 0 );..."
The child at index 0 doesn't exist with the aforementioned code, which throws an exception and the test actually passes, where your intention was for it to fail. That's why I ammended the method so that changing the index will toggle a pass/fail outcome.
Patrick