Unit Testing with FlexUnit


Introduction

FlexUnit is an open source framework created by Adobe for unit testing in Flex. It is based on the widely used JUnit testing framework for Java. FlexUnit provides a low level automated testing system that is your first line of defense for catching bugs in your application.

The concept of unit testing has been around for a long time as part of the traditional Waterfall model of software development. However, it has gained in popular recently as one of the main tenets of Extreme Programming. In Extreme Programming you write unit tests first and then your code. You also refactor code often as you add features. Unit tests help find errors quickly as code is refactored and can be used as part of regression testing to make sure new code has not affected existing functionality.

Unit testing can be automated and included as part of the build process. To facilitate automated building Adobe has created Flex related tasks for the popular Ant build tool. Using Ant you can automatically compile and test your Flex applications.

Unit testing is not the end all be all of testing. It is used to catch low level errors, but there are many classes of errors that are outside its ability to detect such as integration errors, system errors, and performance issues.

What is Unit testing?

To understand unit testing, you must first understand what a “unit” is. A unit is the smallest piece of code that is testable. This doesn’t mean each line of code, but a piece of code that performs a specific task. In Flex, this means a function, or more appropriately a method since Flex/ActionScript is an object oriented language. Unlike many other forms of software testing, unit tests are usually completed by the developer. The developer tests code at a low level to make sure each method is performing as expected. In theory, if each function is working properly at a low level then the higher levels of integration testing should have fewer errors.

Test Subject

Before we talk about how to set up FlexUnit we need something to test. Below is a simple bank account class that will be used as an example. The class allows you to make deposits, withdrawals, and keeps track of your balance.

BankAccount.as

package
{
 	public class BankAccount
 	{
  		var private balance:Number=0;

  		public function deposit(amount:Number){
   			balance=balance+amount;
   		}

  		public function withdraw(amount:Number){
   			balance=balance-amount;
   		}

  		public function getBalance():Number{
   			return balance;
   		}		
  	}
}

Getting Started with FlexUnit

There are four steps necessary to gett FlexUnit running in a project:

1. Download FlexUnit and include the library
2. Create unit tests
3. Create a test suite
4. Create a test runner

Including the FlexUnit Library

FlexUnit is available for download on Google Code at http://code.google.com/p/as3flexunitlib/. After you extract the file from the zip, you will find a flexunit.swc in the bin directory. You need to add this library to your project. If you are creating a new project you can specify libraries as part of the project creation. On the second screen of project creation there is a Library path tab, click on this tab and then select the Add SWC button. This will open a file dialog where you can select the SWC file. If you have an existing project you can set the library up in the project properties. Right click the project, select properties. On the left hand side in the properties menu select Flex Build Path and then the Library path tab. Use the Add SWC button to add flexunit.swc.

The process is simpler for Flex 3 users. Once you have downloaded the flexunit.swc you simply copy it into the libs directory of your project.

Create Unit Tests

Next we create our unit tests. Our unit tests will be contained in a new class that extends the base TestCase class. I’m going to call it BankAccountTest. This class will contain methods with our unit tests in them. You typically create a new method for each unit you are testing. In this case I’ll be testing the deposit and withdraw methods of the BankAccount, so my test class method names will be testDeposit and testWithdraw. The method names for our test methods must start with the word test. Later on when we add the unit tests to the test suite it automatically looks for method names that begin with the word test. If your method names do not begin with the word test they will not be run.

We know we are going to have two test methods, but how do you actually create a unit test? A unit test is made up of logical assertions. If an assertion is true, the unit test passes. If an assertion is false then the unit test fails.

There are several assertion methods available for our unit tests such as: assertTrue, assertFalse, assertNull, assertEquals, and several others. The methods are all similar and take an optional text message and Boolean test of some type. Although text messages are optional, it’s a good idea to use them to help you quickly locate which test failed. If the result of the Boolean test is true, the assertion succeeds, and if not it fails. For example, if I create a BankAccount and deposit fifty dollars, then my balance should be fifty dollars. The unit test for this case is:

var bankAccount:BankAccount=new BankAccount();
bankAccount.deposit(50);
assertTrue(“Balance on a new account after 50 deposit is 50”, bankAccount.getBalance() == 50);

This test is pretty straight forward. If my balance isn’t 50 after I deposit 50, then either I have a problem with deposit method, or my getBalance method. For this sample I only have a few assertions, but you typically want to cover as many cases as possible. This is what my final test class looks like with a few more tests added:

BankAccountTest.as

package {

  	import flexunit.framework.TestCase;

  	public class BankAccountTest extends TestCase {

    		/**
    		 * Test Deposit
    		 */
    		public function testDeposit():void {
   			var bankAccount:BankAccount=new BankAccount();
   			bankAccount.deposit(50);
   			assertTrue("Balance on a new account after 50 deposit is 50", bankAccount.getBalance() == 50);
   			bankAccount.deposit(25);
   			assertEquals("Balance after 50 deposit and another 25 deposit is 75", 75,bankAccount.getBalance());

      		}

    		/**
    		 * Test withdraw
    		 */
    		public function testWithdraw():void {
   			var bankAccount:BankAccount=new BankAccount();
   			bankAccount.deposit(100);
   			bankAccount.withdraw(50);
   			assertTrue("Balance on a new account after 100 deposit and a 50 withdraw is 50", bankAccount.getBalance() == 50);

      		}

    	}
}

Creating the Test Suite and Test Runner

Now that we have our unit tests we are going to create a test suite and our test runner. We will do this in a Flex file instead of an ActionScript class. First we create a simple Flex application which only has one component, TestRunnerBase, which is part of the FlexUnit library. Make sure you include the flexunit name space flexunit.flexui.* in your application so you can access the GUI components from the library. Next we must add functions to set up the test suite and start the testing. We create a createSuite method to create a new TestSuite object and adds all of our TestCase classes to it using the addTestSuite method. The addTestSuite method uses reflection to find all the methods in the class that start with the name test and adds them to list of tests to run. We only have one TestCase class (the BankAccountTest.as we created above), but it you had others they would go in this function as well. Finally we create an onCreationComplete method that is called on the creationComplete of our main application. This function sets the test property of the TestRunnerBase object to our test suite that is returned by the createSuite method. Now we start the testing by calling the startTest method on the TestRunnerBase component. The code should look like:

TestRunner.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
				xmlns:flexunit="flexunit.flexui.*"
				creationComplete="onCreationComplete()">

	<mx:Script>
		<![CDATA[
			import flexunit.framework.TestSuite;

			// Create the test suite and run the tests
			private function onCreationComplete():void
			{
  				testRunner.test = createSuite();
  				testRunner.startTest();
  			}

			// Creates the test suite to run
			private function createSuite():TestSuite {
  				var testSuite:TestSuite = new TestSuite();

  				testSuite.addTestSuite( BankAccountTest );

  				return testSuite;
  			}	
		]]>
	</mx:Script>

	<!-- FlexUnit GUI Component -->
	<flexunit:TestRunnerBase id="testRunner" width="100%" height="100%" />
</mx:Application>

Now we are ready to run our test cases. The following image shows an example of the TestRunner GUI when it is run.

fig1unit.png

A Successful Test

Because our tests are simple and run fast, the progress bar is filled almost immediately. When slower tests are run the progress bar will fill as the tests run. It will also display the number of tests that have been run and the total number of tests. If a test fails, the progress bar turns red and you will see a stack trace of the failed test. The default view shows tests that have failed, but you can also click the All Tests tab to see a list of all the tests that have run.

fig2unit.png

A Unsuccessful Test

For this run I changed the first unit test to check for an invalid balance:

assertTrue(“Balance on a new account after 50 deposit is 50”, bankAccount.getBalance() == 40);

This of course is incorrect and the assertion generates an error. You can see the stack trace for the test that failed in the right hand text area of the GUI. In the first line you can see the text from our assertion:

Error: Balance on a new account after 50 deposit is 50 – expected true but was false

Since no line number is included in the stack trace, you should make sure you use good descriptions in your assertion text. Once an assertion in a test method fails, the method is considered to have failed and no further tests are run in that method. However, any other test methods (even from the same class will) still run.

Conclusion

FlexUnit provides an automated way to test code at a low level. It provides a framework to automate testing that would otherwise be very time consuming and helps find bugs much earlier in the development process. The example in this article introduces the basics of unit testing with Flex, but it opens the door to many interesting possibilities such as test driven development and automated testing during the build process with tools such as ANT.

Additional Resources

FlexUnit on Google Code
http://code.google.com/p/as3flexunitlib/

Extreme Programming
http://www.extremeprogramming.org/

Ant
http://ant.apache.org/

Flex Ant Tasks
http://labs.adobe.com/wiki/index.php/Flex_Ant_Tasks

Advertisements

~ by mjcprasad2000 on July 16, 2009.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: