Code Slinger: A DP Blog

FlexUnit 4.1 Beta 1 Now Available

Posted At: June 7, 2010 6:06 PM | Posted By: Michael Labriola
Related Categories: Adobe Flex, FlexUnit

For months now the core FlexUnit team and contributors have been working diligently to move the next release of FlexUnit forward. The 4.0 release was a success but we always knew there were many optimization and enhancement still to come. Today, we are happy to announce some of those are available as the 4.1 public beta begins. You can download the latest bits from the flexunit.org download site. Here are a few feature descriptions and bullet points of some of the new features in the FlexUnit 4.1 world.

Parameterized Testing

There are times when you need to repeat a test across a series of data points. Imagine a class that does a complex calculation based on input values. It is likely that you would want to test hundreds or thousands of different input values, checking each of their expected outputs to feel comfortable that this class was behaving properly. Or, perhaps you have a whole series of components which implement an interface and you wish to verify that setting the ‘x’ property on each of those objects dispatches and expected event or updates a given property. These are both cases where Parameterized testing can simplify your life. Parameterized testing in FlexUnit works by allowing you to specify arguments to be passed to a constructor (we call it JUnit style), or arguments which will be passed to a method (TestNG Style). Here is a quick sample of the approach:

Constructor (JUnit Style):

[Parameters] public static function data2():Array { return [ [ 3, 6 ], [ 4, 8 ], [ 5, 10 ], [ 6, 12 ] ]; } private var _input:int; private var _expected:int; public function TestParameterized( param1:int, param2:int ) { _input = param1; _expected = param2; } [Test] public function doubleTest():void { assertEquals(_expected, _input*2); }

Method (TestNG Style):

public static function dataThree():Array { return [ [ 0, 1, 1 ], [ 1, 2, 3 ], [ 2, 4, 6 ] ]; } [Test(dataProvider="dataThree")] public function addTwoValuesTest( value1:int, value2:int, result:int ):void { assertEquals( value1 + value2, result ); } Parameters are defined by static properties containing arrays of arrays. The framework iterates through the array, calling your methods with the parameters of each inner array. Parameterized testing can be combined with the asynchronous testing for very complex testing. At first glance, those of you familiar with theories might see a lot of similarities to parameterized testing; they also allow a developer to create methods and a constructor that accept parameters. A theory is different in how the data is defined and in the way a test fails. A theory is akin to a mathematical theory wherein any failure means the whole theory is bad. Further, theories are often reversible. For instance, a valid theory might entail testing a math class by first multiplying two numbers and then dividing the product by the first number. If your code is valid, you should get the second number back. Testing this across a potentially infinite number of values is the real of a theory. Whereas theories see all of the datapoints as input to a single test, which passes or fails as a whole, parameterized testing expands your set of parameters to individual tests allowing you to understand which cases fail and succeed individually. Parameterized tests are more useful in cases where you have a fixed data set with known specific values which represent a valid outcome.

External Data for Parameterized Testing and Theories

Executing tests across large data sets necessarily involves maintaining that data. FlexUnit 4.1 allows the data for Theories and Parameterized tests to be loaded from an external source. public static var dataRetriever1:IExternalDependencyLoader = new ParamDataHelper( "PurelyFakeExample.xml" ); [Parameters(loader="dataRetriever1")] public static var someData:Array; The IExternalDependencyLoader interface works with the Theory and Parameterized test runners to facilitate asynchronous loading of data points before testing begins.

Rules Implementation

When creating large suites of unit tests, you could find yourself duplicating complex setup code many times. Rules offer the ability to factor this code into a separate class and specify logic that will be invoked before or after each test method call, allowing you to alter how a method is called, perform additional setup or even examine and change the result of a test runner. [Rule] public var rule1:IMethodRule = new SomeRule(); [Test] public function test1():void { } This feature can be used to create new types of test runners through composition instead of inheritance, allowing more flexibility, less code to maintain and the ability to reuse the rule across many types of runners. The first application of this technology was the auto-creation and verification of Mocks for test cases, however, the next application is a Rule to inject dependencies into cases.

Directory Scanning and Test Loading

Using the FlexUnit Ant tasks, you can point FlexUnit at a directory, which it will recursively scan for tests, build a temporary suite and execute on your behalf, removing the need to maintain static lists of tests in many cases. <flexunit workingDir="${bin.loc}" toDir="${report.loc}"
 haltonfailure="false" verbose="true" localTrusted="true">
  <testSource dir="${main.src.loc}" />
  <testSource dir="${test.src.loc}">
   <include name="**/*Test.as" />
  </testSource>
 <library dir="${lib.loc}" />
</flexunit>

Performance Improvements

FlexUnit 4.1 now executes FlexUnit 4.x style metadata tests approximately 60% faster than before. New logic that directly monitors the progress of tests throughout the Flash Player frame allows the framework to better utilize the available time, resulting in an additional significant performance boost. Collectively these improvements can halve the execution time on very large suites over previous versions.

UIImpersonator for AS or Flex

Flex developers have had the ability to use the UIImpersonator classes to allow components to interact with the display list since version 4.0. Version 4.1 extends that coverage and allows ActionScript only projects the same access. A new property on FlexUnitCore allows developers to indicate the visual display root of the application, thereby allowing this access. var core:FlexUnitCore = new FlexUnitCore(); core.visualDisplayRoot = this;

Asynchronous Functionality now Available in Parameterized Testing and Theories

The ability to test asynchronously is imperative in Flash, where operations are often broken across frames. FlexUnit Asynchronous methods are now available in Theories and Parameterized Tests.

Package level assertions

You may have noticed that throughout these examples, we have simply said assertTrue() instead of Assert.assertTrue() Package level assertions now exist for all assertion methods, minimizing typing and porting from previous versions of FlexUnit or Fluint.

Timing information during test run

Timing information is gathered internal to the framework during test run, allowing for more accurate measurements of test execution time. Now, go download the latest bits from the flexunit.org download site and give us some feedback.
Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • PDF
  • RSS
  • email
  • Technorati

Comments (3)

3 Responses to “FlexUnit 4.1 Beta 1 Now Available”

  1. Roland Zwaga says:

    Hey Michael,

    I just finished a metadata scan to as3commons-bytecode:

    http://code.google.com/p/as3-commons/source/browse/trunk/as3-commons-bytecode/src/main/actionscript/org/as3commons/bytecode/reflect/ByteCodeType.as

    Perhaps this could be useful for Flex Unit 4? It would remove the need to add a [Suite] class that declares all of the different test classes.

    All you’d need to do is this at application startup:

    var metaDataLookup:Object = ByteCodeType.metaDataLookupFromLoader(FlexGlobals.topLevelApplication.loaderInfo);
    var definitionNames:Array = metaDataLookup['Test'];
    for(var i:uint=0; i < definitionNames.length;i++){
    /* … do something… */
    }

    cheers,

    Roland

  2. Roland Zwaga says:

    Hey Mike,

    Isee your point indeed, the only way this would work is if the tests would be loaded in a separate RSL. Which might make sense in REALLY large projects, but not accross the board.
    Consider my comment unwritten :)

    cheers,

    Roland

  3. michael labriola says:

    Roland,

    This is very cool but unfortunately it won’t remove the need for suite. The purpose of the suite is two fold. First, it is a mechanism to ensure linking. Without the concept of the suite, your scanning wouldn’t work as the tests would have no reason to be linked into the final swf file. Second, the suite is for organization. When tests get very numerous, making easy hierarchical decisions about which to run is invaluable. We have the ability to scan a directory to find all of the tests and build a swf, but it has limited practical use as the number of tests in your system gets large.

    Mike

Leave a Reply