Home >
Software developers are a lazy group of people. It’s true. It’s what makes us good at our job. We have an intrinsic need to find an easier, or at least faster, way to do things. Of course, we also tend to be a stubborn group of people. It’s rare that someone can change our mind, we usually need to experience something ourselves to understand why it matters.
That’s what this series of articles is about. I will tell you the reasons that my team writes tests. I will tell you what we get out of it. However, I will also show you that the barrier to entry is small and that writing tests is something you can try without a big commitment. Perhaps this low barrier will allow you try it on a project. Once you have had the chance to try it, you can better decide for yourself if the initial effort is worth a faster/easier way to develop later.
Prerequisites
- Adobe Flex Builder 3
- Basic Knowledge of Flex and ActionScript
The Truth
Developers always test their code; however, they usually do so in a very narrow way. They make changes to a section of code and exercise that section until they believe it works. They work within an existing application or, if it is very complicated, they might make a simple test program to interact with that section. When that piece of code works correctly, they leave it alone and rarely return to retest it unless they believe it might break.
This unfortunately means that many pieces of code are written and then left untouched for the duration of the project while the developer believes that everything still works perfectly. As changes are made to other areas of the application much of this code is subject to inadvertent corruption, only to be found after the developer or team has long forgotten how this particular piece works
The Approach
This article is going to demonstrate unit testing using the Fluint (Flex Unit and Integration) framework, which is an opensource project hosted at http://fluint.googlecode.com. The next articles will address asynchronous and integration testing with Fluint, integration testing with Quick Test Prop and finally code coverage. However, most of the concepts are applicable regardless of which tools you use to test.
This article is specifically talking about tests that are written by developers using ActionScript. They are designed to be run often and without any user interaction. These are not the type of tests written by a Quality Assurance (QA) operator without coding experience; those will be covered in later articles.
The Sales Pitch
My team writes a lot of tests. In fact, we once took an entire month in an already overloaded schedule to beef up the number of tests we had for a key project. We do it for a few very simple reasons:
It allows us to test much more often than we could do so manually.
There are only so many hours in the day. Code that hasn’t been exercised in a while is always suspect. Regardless if you are working as a lone developer or as part of a team, you will likely end up yielding on features somewhere in the process to make a deadline. If features are lost from a project, what are the odds that manual testing that takes developer time will remain a high priority?
When you create automated tests they can be run constantly. After the tests are created, code can be executed continually, immediately alerting you if a new change breaks another piece of code.
It is cheaper than hiring teams of QA folks to execute tests continually.
Automated tests cost money to write, however, it is a one-time, non-recurring, expense. Once a test is written, you can run it forever for a near zero cost. Contrast this to manual testing which costs little in the beginning, but re-occurs every time you wish to test.
It reduces the time to find and squash bugs.
Automated tests can run continuously. This means that if a developer creates a bug, it is likely to be caught in a very short period of time. This is important for two huge reasons. First, developers are always solving the next problem. If you wait weeks or months before discovering a bug, you need to re-find and re-learn code. A bug that might have taken moments to solve when you first wrote it could now take days or more. Second, the longer you wait to resolve a bug, the more likely it is that more code will need to be touched.
For example, if I make a mistake in a simple base class which is then extended dozens of times and used in even more classes, each of those is now subject to issues. As a corollary to this item, the possibility always exist that fixing a bug may require a major change or an interface change. This could invalidate all of the work that followed.
It allows us to change and rewrite code without fear of breaking something else.
Imagine discovering a better performing, or simply a better, way to accomplish a task. As a developer you would likely wish to implement this strategy. However, if that code is used in hundreds, or hundreds of thousands, of places how can you be sure you won’t utterly destroy a project? Or more likely, how can you be sure that it won’t just break three important cases in some obscure class that is rarely touched? If you have sufficient test coverage of your application, you can change almost anything. If the tests still succeed, your code still works. That is the key to sleeping at night.
It increases the quality of the software we write.
Code that has sufficient automated tests is less likely to be deployed with major bugs. The application will have been tested thousands of times in the course of development. As with most software, bugs will still exist, but they are less likely to be fundamental and noticeable.
Ultimately, we appear to be more effective developers to our clients.
When we deliver solid code that works the first time we are perceived as effective developers. This has implications ranging from the rate we can request to the likelihood of landing that next huge client. Tools that help you become better at what you do should always warrant serious consideration.
Installing Fluint
Fluint is a testing framework which is available for download as ActionScript source or as a compiled SWC library file. This article uses the library.
- 1) Create a New Flex Project
- 2) Download the fluint_v1.swc to the libs folder of your new project. You can find the fluint_v1.swc from the Downloads tab on http://fluint.googlecode.com.
- 3) Download the FlexTestRunner.mxml from the same location and save it into your project’s src directory.
- 4) Inside of Flex Builder, right click or control click on the FlexTestRunner.mxml and set it as the default application
When these steps are complete, your directories should look like the following image.

The fluint_v1.swc is the compiled fluint framework. It provides the base and helper classes to create tests. The FlexTestRunner.mxml provides you a sample way to run your tests and display the results to the user. Fluint provides the tools to run these tests and information about the success or failure of each test, but you are free to use and display that information in any way that you would like.
You can run the FlexTestRunner at this point. The application will start and execute a series of test designed to ensure that the framework is working properly.
Tests in Fluint are divided into test suites, test cases and test methods. Multiple test methods collectively comprise a test case. Multiple test cases comprise a test suite. Your test runner can then run multiple suites and report on the results. Using the tree on the left hand side you can explore the cases and methods of the framework test suite or you can click on the individual boxes of the green progress bar on top of the page. A green box in the progress bar indicates the test passed. A red box indicates a failure.
When you click on an individual test method, the trace panel on the right gives information about its success or failure. If it succeeded, you will receive information regarding the amount of time it took to execute. If it fails, you will receive the error message as well as the stack trace that occurred before the failure.
Creating a Unit Test
Unit tests are designed to test the smallest unit of a program. This usually means a single method or function. Let’s start by making a new class to test.
Making a Testable Class
- 1) Create a new folder called ‘helper’ inside of the src directory of your project
- 2) Inside of the helper folder, create a new ActionScript class named BasicMath.as
- 3) Add a new public method in your BasicMath class file called AbsoluteValue(). The method should accept a single argument named value of type Number and return a Number.
Note: At this point you have a choice dependent upon your development methodology. Fans of test driven development believe you should create your tests now, before you write the code for this method. The theory is very simple: If you write tests that validate how a method should work then the method can be declared functional when the tests pass. This is a good philosophy, but it is outside of this article which is simply designed to demonstrate testing. Spend some time and learn more about this concept.
public function absoluteValue( value:Number ):Number { }
- 4) Inside of the method, check if the number is greater than or equal to 0. If it is, simply return the number. If it is not, then return -1 multiplied by the original number.
You now have a class and a method that can use some testing.
public function absoluteValue( value:Number ):Number { if ( value >= 0 ) { return value; } else { return ( value * -1 ); } }
Creating a test method, case and suite
- 1) Create a new directory in your src folder named mathSuite
- 2) Inside of the mathSuite folder, create a folder named tests
- 3) Inside of the tests folder, create a new ActionScript class named TestAbs using net.digitalprimates.fluint.tests.TestCase as the superclass.
- 4) Create a new public method inside of the TestAbs class named testPositiveNumber() with a void return type.
- 5) Inside of the method declare a new variable named basicMath of type BasicMath and instantiate it.
- 6) Next declare a variable named newValue of type Number.
- 7) Finally, call the absoluteValue method of the BasicMath instance passing the number 5 as an argument. Set the return type equal to newValue.
public function testPositiveNumber():void { var basicMath:BasicMath = new BasicMath(); var newValue:Number; newValue = basicMath.absoluteValue( 5 ); }
- 8) The last step in this test is to make an assertion. As assertion is your declaration to the framework about the state of things at this point in the test. In this case, you will add the following code as the last line of this method:
assertEquals( newValue, 5 );
In other words, you are stating that newValue should be 5 at this point, if this test is to be considered a success.
As the name of this method begins with ‘test’, the fluint framework will, by default, understand that you intend this method to be executed as part of this test case. Creating a class that extends from TestCase and has at least one method means that you have successfully created your first test case. Next, you must add this test case to a test suite for execution.
- 9) In the mathSuite directory you created earlier, create a new ActionScript class named MathSuite designating net.digitalprimates.fluint.tests.TestSuite as the super class.
- 10) Add an import statement to the top of this class for the test case you created above:
import mathSuite.tests.TestAbs; - 11) In the constructor of the MathSuite class, use the addTestCase() method of the TestSuite super class to add a new instance of your TestAbs class.
In this example, the MathSuite now contains a single test case, which in turn has a single method. However, in a real test environment, your suites may have hundreds of cases, each with dozens or hundreds of methods.
public function MathSuite() { addTestCase( new TestAbs() ); }
- 12) The final step to before executing your test is to add your new test suite to the test runner’s queue. To do this open the FlexTestRunner.mxml file and find the startTestProcess() method. This method is responsible for creating an array and passing it to the startTests() method of the testRunner.
- 13) Currently, a new instance of the FrameworkSuite is instantiated and added to the array. Change this code to add a new MathSuite() instance to the array.
Note: You could add both the MathSuite and FrameworkSuite to this array. In that case, both suites would run and provide results.
protected function startTestProcess( event:Event ) : void { var suiteArray:Array = new Array(); suiteArray.push( new MathSuite() ); testRunner.startTests( suiteArray ); }
- 14) Run the FlexTestRunner application. If you typed everything correctly. Exactly one test should run and report a success.
Finishing your Test Case
Right now you have a single method inside of your test case. Unfortunately, one test method is not enough to test even your simple absoluteValue() method. Inside of the absoluteValue() method, you have an if statement. If the value is greater or equal to zero, you return the value, else you return the value multiplied by negative one. Currently you are testing one path through the method but not the other. In practice, you will need a test for each possible path through a method.
To rectify this issue:
- 1) Open the TestAbs test case
- 2) Add a new public method to this class named checkNegativeNumber().
- 3) Duplicate the functionality of the testPositiveNumber() method
- 4) In this method, pass a -5 to the absoluteValue() method. Your method should look like the following sample:
public function checkNegativeNumber():void { var basicMath:BasicMath = new BasicMath(); var newValue:Number; newValue = basicMath.absoluteValue( -5 ); assertEquals( newValue, 5 ); }
- 5) This method name does not start with the word test, so it will not automatically be recognized by Fluint. To rectify this problem, you can add the [Test] Metadata to this method. Doing so indicates that you intend this method to be executed as a test.
[Test] public function checkNegativeNumber():void
- 6) The [Test] Metadata provides additional functionality not available when simply starting your methods with test. You can pass descriptions of the test and other information along with the test which will later be available in the user interface. For example to pass a description and potentially a bugID that this test addresses, the metadata would look like the following:
Using this syntax, you can pass any attributes you wish along with the test. They will all be available later for retrieval.
[Test(description='This checks negative numbers',bugID='33')]
- 7) If you run the FlexTestRunner at this point, you will see two passing tests.
Setting Up and Tearing Down the Test Case
Right now your tests work fine; however, you are recreating an instance of the BasicMath class in each method. For this simple example that isn’t a big deal, but if you had a complex series of steps to execute before each test, it would become difficult to maintain these at the beginning of each of your test methods.
For this purpose, the test case has two methods that can be overridden named setUp() and tearDown(). The setUp() method can contain any work that must be performed before each test method is run. The tearDown() method cleans up any objects created in the setUp();
The setUp() and tearDown() are called for each test method. So, using this example, the execution order would be as follows:
- setUp()
- testPositiveNumber()
- tearDown()
- setUp()
- checkNegativeNumber()
- tearDown()
Using these methods, your new test case would appear as follows:
private var basicMath:BasicMath;
override protected function setUp():void {
basicMath = new BasicMath();
}
override protected function tearDown():void {
basicMath = null;
}
public function testPositiveNumber():void {
var newValue:Number;
newValue = basicMath.absoluteValue( 5 );
assertEquals( newValue, 5 );
}
[Test(description='This checks negative numbers',bugID='33')]
public function checkNegativeNumber():void {
var newValue:Number;
newValue = basicMath.absoluteValue( -5 );
assertEquals( newValue, 5 );
}
Next Steps
This article introduced the basics of creating developer unit tests. However, basic unit tests are only the tip of the testing iceberg. In future article, I will cover asynchronous unit, integration and functional testing. In the meantime, you can learn more about the advanced features of Fluint at http://fluint.googlecode.com.





Facebook Application Development
Nice article. I agree with most things you say, however, I disagree about the one-time cost of maintaining tests.
I find that unit tests need to also be maintained as the app grows, just as the source code. I'm not just talking adding new tests for the new functionality, but maintaining the old tests. This is very true whenever you have unit tests around the service layer. There's just no way of changing the contract with the server on data without it affecting how the client uses and needs it. In fact in complex integrations with the back-end, I've found that maintaining the unit tests that go along with it take about as long as making the actual code changes to support it. Which isn't necessarily a bad thing, it's just not close to zero cost. Which is why it's important that clients know they're actually paying for such support and that developing UNIT tests is actually a cost to the project. (Those 50% of the code base in unit tests just don't write themselves.) In 15 years of software development, I've yet to see a service/backend layer not change during the lifespan of an application.
Also, Unit testing isn't a substitute for having a QA team operating the application in a live environment with the intended UI. This is especially true for a RIA that's so dependendent upon an organic user interface. Unless there's a product around (I'm not aware of any) that drags-and-drops, enter's characters in input boxes, expanding tree's and populating with sub-items, etc...For flex, it's just not possible to effectively test a front end (like it is when writing pure HTML apps). Unit testing "may" reduce the amount of QA testing, but it far from eliminates QA.
Anyway, I look forward on what you have to say about testing all the Asynchronous stuff, as I've found it's a real PITA from Flex (except for services).
This was a very timely article - I'm currently taking a class on software quality analysis, and at work, I'm just getting into Flex.
I think it's better to position Fluint as you described it, as a way to increase your productivity by improving your testing process. You would still need to do black-box testing on your Flex app just as you always have; unit testing and automation are really tools that help you with white-box testing.
Do you have any experience with Selenium? At the last place I worked, we were just starting to get into that with respect to testing CF/HTML apps. I don't know if it has the ability to track events in a Flex app the same way it interacts with HTML ...
Todd:
Agree with you completely. Didn't mean to imply there is no cost for maintenance of tests but rather almost no cost to continue to execute a test that is still valid. When a requirement, or approach to solving, changes, the code and test will change and there will be cost. However, in the end it is still worth the effort.
Also totally agree on the QA team needing to be involved. However, I am in favor of using a QA team efficiently. So, I would rather have them looking at code that passes a huge set of tests then let them try to tackle and retest every nook and cranny of something that will likely break.
Dave:
I don't have expeience with Selenium, however, a member of the Fluint team has been exploring some ways to borrow ideas from Selenium in the way we write Sequenced tests, so, hopefully I will know more about that soon.
Mike
Somehow when I tried the setUp and tearDown I got this error:
1023: Incompatible override. test_fluint/src/mathSuite/tests TestAbs.as line 14 1224274632499 26598
Everything else worked. Any ideas?
Damian,
It should read override *protected* function setUp and tearDown, not public. I will try to get this fixed in the article.
Mike
Hi! this tutorial was very nice and clear. Can you post some uml secuence diagram of how functions are called?. Thanks!
var z:int;
var a:String = new String('30');
z = c + x ;
assertEquals(z,a);
it returns true . Can't it differentiate between integer and string ???
tell me if i am doing it in a wrong way ... ???
knock knock .
When you do a comparison like this the player is going to try to convert the types to something that is comparable.
Take a look at the the operand docs, including things like the == and === and the != and !== for strict equality and inequality.
Mike
I know about operands very well . Few things i would like to know about Fluint.
# Where can I get the API Docs to know the classes and methods of Fluint.
# As told in your tutorial I am passing assertEquals(z,a); liek this.
So as u are saying me to check about operands ...Can I pass here like
assertEquals(z==a) ; ???
Is this what you have suggested in above reply ???
I hope you will respond soon !!
Thanks & Regards !
Amar Shukla
My point is that Fluint is not converting those items for you, rather Flash Player is. It understands how to do some of these implicit conversions for you.
Look at these three tests:
public function testStringNumberEquals():void {
assertEquals( 8, String("8") )
}
public function testStringNumberStrict():void {
assertStrictlyEquals( 8, String("8") )
}
public function testStringNumberStrictConvert():void {
assertStrictlyEquals( 8, Number( String("8") ) )
}
The first one will pass as the assertion simply looks for equality. The second will fail as we are looking for strict equality. The third will succeed because we manually ensure the types are the same.
The docs are checked in with the source on the fluint project. As soon as possible, we will also make them available in the downloads section as a separate zip file.
Hope this helps,
Mike
Wow, flex seems to be a great platform. I will definitely look into this.
MikeCrabe
Is Part 2 out yet? I'm looking for Fluint and integration tests.
Thx.
Wow, thank you for all of these great tips, and for all your hard work that went into this post. I had no idea about flex, and it seems that it will be a great platform for me to use. Thanks!
Thanks for the great instructions. Who knew it could be so easy. I have been trying to figure this out for awhile. Flex has answered my prayers.