After completing my preso at 360|Flex San Jose I realized how many people are having difficulties starting with Test Driven Development (TDD). I had many people walking up to me and telling me about their interest of starting using TDD and how it’s hard to get started. I decided to share my knowledge. This blog entry includes the following:
- Complete Tutorial building a “real life” application
- My 360 presentation
- Complete Project
You can download the doc, preso and project files from here:
http://eladelrom-preso.googlecode.com/files/TDD.zip
The presentation is avaliable below:
Let’s get started.
As Flash applications become more dynamic and complex, they become more difficult to maintain and scale, particularly when business requirements change throughout the course of development. These challenges are significant and they are common in all types of development, including mobile, web, and desktop applications.
For software engineers, this problem is neither new nor confined to a specific platform. Java and ASP developers have been challenged with the same issues and have found Test Driven Development (TDD) a useful technique for creating applications that can be easily maintained.
Luckily, 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/).
FlexUnit 4 allows you can create tests in order to achieve reliability, stability and maintainability of your application, however without proper understanding how to create tests and how to shift your coding style you will not be able to fully take advantage of FlexUnit 4.
The purpose of this wiki page is to give you the tools you need to shift your coding style and start using FlexUnit 4 to the fullest.
Test Driven Development quick overview
That’s exactly where TDD (Test Driven Development) comes in, but what’s TDD anyway? In short, the concept is pretty simple. You write your tests before you write your code. It’s that simple and worth repeating: write tests before code!
Test Driven Development is a software development technique in which programmers are writing a failed test that will define the functionality before writing the actual code.
Furthermore, TDD is about realizing an act of hypocrisy. As software developers our job is to be lazy. We automate repetitive tasks.
Yet the balance of the time spent developing code is actually spent testing and debugging our code manually (80% as some studies suggest). Why would you choose to do this repetitive and annoying task when you automate all of the others?
What it means is that we can let humans do the work they do best while letting computers do the work they do best and ending up with code that is more stable and more maintainable.
The concept of TDD is based on Extreme Programming (XP) development paradigm, which talks about teams that work on the development of dynamic projects with changing requirements and a development cycle that includes TDD for writing the test before the code itself. TDD is not the complete development cycle; it is only part of the Extreme Programming (XP) development paradigm. Preparing the tests before writing the code helps a development team to demonstrate their work in small steps, rather than making the customer or other stakeholders wait for the complete result.
Moving in small increments also makes it easier to accommodate changing requirements and helps ensure that your code does what it needs to do, and nothing more. It is important to mention that the focus of the TDD technique is to produce code and not to create a testing platform. The ability to test is an added benefit.
TDD is based on the idea that anything you build should be tested and if you are unable to test it, you should think twice about whether you really want to build it.
By now, there are many resources that explain how to create simple application, in order to implement TDD, however I yet to find a tutorial that gives a real application so I decided to use a real life example so you can better understand FlexUnit and TDD. While trying to come up with an example I realized that one of my tasks these days is to create an AIR application similar to Adobe MAX Companion AIR Application for a conference I am organizing called: FlashAndTheCity (http://www.flashandthecity). Creating a real application can show you how does the process goes in real development and not in a fake example that tries to make everything simple and easy, since creating applications is complex and change often even as you build your application.
Defining Application’s Objective
Understanding the application objectives is as important as coding your application. Here’s a lessons we can learn from a Master Carpenter: Measure Twice, Cut Once!
You need to understand what you are developing before you get started. In our case, we are building an application that will do the following:
1. Allow attendees to communicate with each other through twitter API.
2. The class will keep a list of tweets with #FlashAndTheCity hashtag
3. The class will check for updates of tweets often
Take a look at the Adobe MAX Companion AIR application (Figure 1), the application we are building is very similar in functionality.

Figure 1: Adobe MAX Companion AIR application
In order to understand the problem we need to be able to explain the problem in an everyday language.
User Stories
A good approach to take to ensure the tasks are defined well is to follow Agile software development mythology. The Agile mythologies talks about creating one or more informal sentences in an everyday or business language, this type of approach is known as a User Story. The User Story should be limited in characters and should fit a small paper note card. The user stories are usually written by the client in order to give direction to build the software. Think of this list as your todo list.
In our case here are the User Stories:
1. Retrieve tweets with #FlashAndTheCity HashTag from Twitter API.
2. Have a service call to twitter and retrieve tweets every few seconds.
3. Login into user’s twitter account and retrieve personal information.
4. Store user’s information so user wouldn’t have to login again every time.
5. Post a tweet on twitter from a user
6. Add #FlashAndTheCity Hashtag to a tweet so user wont have to type it every time and the application will be able to retrieve all tweets related to the conference.
7. Keep a list of tweets with the ability to add a tweet & remove a tweet.
Getting started
Creating the application
With the knowledge of what we need to develop we are ready to get started. The first step is to create the application open Eclipse or Flash Builder 4 Beta and create a new project name Companion (see instructions below).
• Select File > New > Flex Project to create the project.
• For the Project Name, type Companion, ensure you set the project as Desktop application type.
• Click Finish.
See figure 2.

Figure 2: Create new Flex project for desktop
Creating the class to be tested
The architecture we will follow is creating a utility helper class that will wrap the Twitter API and provide the ability to access the different methods in Twitter API.
Create a new class and call it TwitterHelper based the class on the EventDispacher super class so the utility class will be able to dispatch events when new tweets are available. (I recommend writing the actual class needed after writing the test, however, I wanted to show the two approaches).

Figure 3: Create new ActionScript Class
Once you select Finish, the class is created automatically for you, see code below:
package utils
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class TwitterHelper extends EventDispatcher
{
public function TwitterHelper(target:IEventDispatcher=null)
{
super(target);
}
}
}
What important more than deciding if you want to create this class or not is to ensure that the helper class is not implemented, since we need to follow TDD process and write the test before we write the actual code. Our next step is to create the Test Suite and Test case.
Creating your first Test Suite
The next step is to create a test suite.
A test suite is a composite of tests. It runs a collection of test cases. During development you can create a collection of tests packaged into test suite and once you are done, you can run the test suite to ensure your code is still working correctly after changes have been made.
To create a test suite, choose File > New > Test Suite Class (see Figure 4).

Figure 4: Creating a new Test Suite Class in Flash Builder 4
After you select New Test Suite Class a wizard window opens up. Fill in the following information:
• In the New Test Suite Class dialog box, name the class CompanionTestSuite.
• Select New FlexUnit 4 Test (see Figure 5).
• Click Finish.

Figure 5: Creating a New Test Suite Class named CompanionTestSuite
Note that Although in Extreme Programming you are encouraged to write tests before creating the code (and ideally that’s how you should work), in real life there are many times where you will find yourself writing the tests after the code. Such decisions are made case by case, and it is OK to adjust the methodology to fit your workflow.
Flash Builder 4 added the following class under the flexUnitTests folder:
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class CompanionTestSuite
{
}
}
The Suite metadata tag indicates that the class is a suite. The RunWith tag instructs the test runner to execute the tests that follow it using a specific class. FlexUnit 4 is a collection of runners that will run a complete set of tests. You can define each runner to implement a specific interface. You can, for example, specify a different class to run the tests instead of the default runner built into FlexUnit 4.
Add your first test case class
Next, you need to create a test case. A test case comprises the conditions you want to assert to verify a business requirement or a User Story. Each test case in FlexUnit 4 must be connected to a class. To create the class, follow these steps:
Create the Test Case class:
1. Choose File > New > Test Case Class.
2. Select New FlexUnit 4 Test.
3. Type flexUnitTests as the package.
4. Type TwitterHelperTester as the name.
5. Type utils.TwitterHelper as the Class To Test (see Figure 6).

Figure 6: Creating a new Test Case class
In case you are creating tests for a class that already existing methods you can select Next and choose the methods you want to test. In our case we are following TDD and creating the test before writing the code so no need to select any methods and you can hit Finish to complete the process and create the Test Case class.
Important: Ensure that there is a reference in CompanionTestSuite.as to TwitterHelperTester:
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class CompanionTestSuite
{
public var twitterHelperTester:TwitterHelperTester;
}
}
You are ready to start writing test code. Open TwitterHelperTester.as and notice that classToTestRef reference has been created automatically for you. Here is the generated code:
package flexUnitTests
{
import flexunit.framework.Assert;
import utils.TwitterHelper;
public class TwitterHelperTester
{
// Reference declaration for class to test
private var classToTestRef : utils.TwitterHelper;
public function TwitterHelperTester()
{
}
}
}
Implementing your User Stories
Retrieve Tweets User Story
We can start with the first User Story, Retrieve tweets with #FlashAndTheCity HashTag from Twitter API. See figure 7.

Figure 7: Retrieve tweets user story
In case you used FlexUnit 1 you recall that each method you create must start with “test”, to enable the test runner to recognize the method. As a result, the method name was changed to testAdditionMethod. In FlexUnit 4, method names do not need to start with “test”; instead they are recognized by the [test] metadata, so feel free to refactor the method names to names that most suite your need.
The first step in implementing the first user story is to understand what’s your goal here. In our case we are testing that the service is working correctly. We are using a public API that is maintained by Twitter and creating a Mashup application. Using a well maintain API helps us creating our application quickly, however it also store a disadvantage that in any time Twitter may change their API and our application will stop working. We are testing that the fail and success events are dispatching correctly and ensuring that the API is working, see the code below:
package flexUnitTests
{
import flash.events.Event;
import flexunit.framework.Assert;
import org.flexunit.async.Async;
import utils.TwitterHelper;
public class TwitterHelperTester
{
// Reference declaration for class to test
private var classToTestRef : utils.TwitterHelper;
public function TwitterHelperTester()
{
}
[Test(async,timeout="500")]
public function testRetrieveTweetsBasedOnHashTag():void
{
classToTestRef = new TwitterHelper();
var EVENT_TYPE:String = "retrieveTweets";
classToTestRef.addEventListener(EVENT_TYPE, Async.asyncHandler( this, handleAsyncEvnet, 500 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
}
//--------------------------------------------------------------------------
//
// Asynchronous handlers
//
//--------------------------------------------------------------------------
private function handleAsyncEvnet(event:Event, passThroughData:Object):void
{
Assert.assertEquals( event.type, "retrieveTweets" );
}
}
}
As you can see we are writing a test that the method that calls the twitter API works and it retrieve results. We are referencing a method that doesn’t exist: retrieveTweetsBasedOnHashTag.
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. Notice that we are setting a meta data with a timeout:
[Test(async,timeout="500")]
The test will wait 500 milliseconds for to get retrieveTweets dispatched meaning that the results have been retrieved.
Working on the compilation errors
Save the file and now you see a compile time error:
Call to a possibly undefined method retrieveTweetsBasedOnHashTag through a reference with static type utils:TwitterHelper.
This is actually a good. The compiler is telling you what you need to do next. We can now create the method in TwitterHelper in order to get rid of the compiler error.
package utils
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class TwitterHelper extends EventDispatcher
{
public function TwitterHelper(target:IEventDispatcher=null)
{
super(target);
}
/**
* Method to send a request to retrieve all the tweet with a HashTag
* @param hashTag defined hashtag to search
*
*/
public function retrieveTweetsBasedOnHashTag(hashTag:String):void
{
// implement
}
}
}
Notice that I only wrote the minimum code to get rid of the compiler error, I haven’t implemented the method yet.
Compile the project and we don’t have any compile time errors and you can run the tests. Select the Run icon carrot and in the drop menu select FlexUnit Tests.

Figure 8: Start FlexUnit tests top menu
Once you selected the Run FlexUnit Tests a wizard gives you the opportunity to select entire classes or individual methods. Select TwitterHelperTester and hit OK, see Figure 9.

Figure 9: Select and run FlexUnit Tests window
Review the Results
Flash Builder opens a new window where the tests are run and shows the results of your test, see below:
• 1 total test was run
• 0 were successful
• 1 was a failure
• 0 were errors
• 0 were ignored

Figure 10: FlexUnit Test Run results
After the result window shows up you can close it and review the results in Flash Builder
• Close the web browser that was opened by builder
• You should see a new view opened in your Flash Builder called FlexUnit Results
• If you don’t see the window select: Windows > Other Views > Flash Builder > FlexUnit Results will open it
• The Results view will show you similar information to the web browser with much more detail and interactivity
• Note the Red Bar and double click on testSampleMethod in the results view (see Figure 11).
• Flash Builder will take you to that method in your code.
• Note that the failure message in the Failure Trace is the same as the contents of the Assert.fail call.

Figure 11: FlexUnit result view in Eclipse
The results view provides several action buttons worth reviewing see Figure 12.

Figure 12: results view options
Change the Test from Fail to Pass
In order to pass the test you now need to write the actual code. At this point we wrote the test and once we write the code the test will succeed. I have implemented the code to call Twitter and retrieve results that includes #FlashAndTheCity hashtag, see below:
package utils
{
import com.adobe.serialization.json.JSON;
import flash.events.EventDispatcher;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
public class TwitterHelper extends EventDispatcher
{
/**
* Holds the service class
*/
private var service:HTTPService;
//--------------------------------------------------------------------------
//
// Default Constructor
//
//--------------------------------------------------------------------------
public function TwitterHelper()
{
// implement
}
/**
* Method to send a request to retrieve all the tweet with a HashTag
* @param hashTag defined hashtag to search
* @url the twitter API url
*
*/
public function retrieveTweetsBasedOnHashTag(hashTag:String, url:String):void
{
service = new HTTPService();
service.url = url;
service.resultFormat = "text";
service.addEventListener(ResultEvent.RESULT, onResults);
var object:Object = new Object();
object.q = hashTag;
service.send( object );
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* Method to handle the result of a request to retrieve all the list
* @param event
*
*/
private function onResults(event:ResultEvent):void
{
service.removeEventListener(ResultEvent.RESULT, onResults);
service.removeEventListener(FaultEvent.FAULT, onFault);
var rawData:String = String( event.result );
var object:Object = JSON.decode( rawData );
var results:Array = object.results as Array;
var collection:Vector.<TweetVO> = new Vector.<TweetVO>;
results.forEach( function callback(item:*, index:int, array:Array):void {
var tweet:TweetVO = new TweetVO( item.from_user, item.from_user_id, item.geo, item.id,
item.profile_image_url, item.source, item.text, item.to_user, item.to_user_id );
collection.push( tweet );
});
// dispatch an event that holds the results
this.dispatchEvent( new TwitterHelperSuccessEvent( collection ) );
}
}
}
Notice that I am using JSON class, which is part of AS3 CoreLib (http://code.google.com/p/as3corelib/)
Additionally, in order to achieve the test I decided to do few things such as creating a Value Object (VO) to hold the results and create a custom event that will be dispatch once the results are retrieved. The VO holds must of the properties retrieved from Twitter API, see complete code below:
package utils
{
[Bindable]
public final class TweetVO
{
public var from_user:String;
public var from_user_id:int;
public var geo:String;
public var id:int;
public var profile_image_url:String;
public var source:String;
public var text:String;
public var to_user:String;
public var to_user_id:int;
public function TweetVO(from_user:String, from_user_id:int, geo:String, id:int, profile_image_url:String,
source:String, text:String, to_user:String, to_user_id:int)
{
this.from_user = from_user;
this.from_user_id = from_user_id;
this.geo = geo;
this.id = id;
this.profile_image_url = profile_image_url;
this.source = source;
this.text = text;
this.to_user = to_user;
this.to_user_id = to_user_id;
}
}
}
Additionally, I have created a custom event that will hold the constant event type and allow passing the collection of tweets received, see complete code below:
package utils
{
import flash.events.Event;
public class TwitterHelperSuccessEvent extends Event
{
public static const RETRIEVE_TWEETS:String = "retrieveTweets";
public var collection:Vector.<TweetVO>;
public function TwitterHelperSuccessEvent( collection:Vector.<TweetVO> )
{
this.collection = collection;
super( RETRIEVE_TWEETS );
}
}
}
Keep it simple: to the sake of simplicity I am keeping all the classes related to our class under the same package but feel free to refactor and place the event under an event folder. Also I haven’t implemented the clone method, which is recommended, but feel free to add these changes.
Run the test again and observe the results, see Figure 13.
• A test that does not fail succeeds
• Click the Run Completed Button
• Observe the Green Bar that indicates success

Figure 13: FlexUnit results view showing green bar
One thing to note is that I have set the service to 500 milliseconds, however the request took longer and I the test still failed so I quickly adjusted the code to wait 20000 milliseconds (20 seconds) to accommodate cases where the network is slow, feel free add a test to ensure the respond is quick enough.
To complete the user story we need to also test fault request, so just as we did before let’s write the test and than implement the code.
Add the following test:
[Test(async,timeout="20000")]
public function testRetrieveTweetsBasedOnHashTagFail():void
{
classToTestRef = new TwitterHelper();
var EVENT_TYPE:String = "serviceFailure";
classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this, handleAsyncFaultEvnet, 20000 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
}
private function handleAsyncFaultEvnet(event:Event, passThroughData:Object):void
{
Assert.assertEquals( event.type, "serviceFailure" );
}
Run the test and watch the fail results. Refactor TwitterHelper to include the fail method.
public function retrieveTweetsBasedOnHashTag( hashTag:String, url:String ):void
{
service = new HTTPService();
service.url = url;
service.resultFormat = "text";
service.addEventListener(ResultEvent.RESULT, onResults);
service.addEventListener(FaultEvent.FAULT, onFault);
var object:Object = new Object();
object.q = hashTag;
service.send( object );
}
/**
* Holds the fault method in case the service failed
*
* @param event
*
*/
private function onFault(event:FaultEvent):void
{
service.removeEventListener(ResultEvent.RESULT, onResults);
service.removeEventListener(FaultEvent.FAULT, onFault);
this.dispatchEvent( new TwitterHelperFailureEvent( event.fault.message ) );
}
Make sure to create the custom event for the fail event:
package utils
{
import flash.events.Event;
public class TwitterHelperFailureEvent extends Event
{
public static const SERVICE_FAILURE:String = "serviceFailure";
public var message:String;
public function TwitterHelperFailureEvent( message:String )
{
this.message = message;
super( SERVICE_FAILURE );
}
}
}
Test again and you should see a green light, see Figure 14.

Figure 14: Result view showing our two test completed successfully
Refactor
At this point, we can do a small refactoring to the test case and include the static method from the custom event instead of having the string attached, which will ensure our tests still pass in case we refactor the event type string, see code below:
[Test(async,timeout="20000")]
public function testRetrieveTweetsBasedOnHashTag():void
{
classToTestRef = new TwitterHelper();
var EVENT_TYPE:String = TwitterHelperSuccessEvent.RETRIEVE_TWEETS;
classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this, handleAsyncEvnet, 20000 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
}
[Test(async,timeout="20000")]
public function testRetrieveTweetsBasedOnHashTagFail():void
{
classToTestRef = new TwitterHelper();
var EVENT_TYPE:String = TwitterHelperFailureEvent.SERVICE_FAILURE;
classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this, handleAsyncFaultEvnet, 20000 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
}
Tests have duplication that can become painful to maintain
• In our case, we need to instantiating TwitterHelper in each test.
• Granted, there are just two, but this will grow
• We can solve this problem by using additional metadata provided by FlexUnit 4 called [Before] and [After]
• [Before] can be applied to any method that you wish called before each test.
• [After] will be called after each test
For good measure, let’s add a method name tearMeDown() and mark it with the [After] metadata.
• The [After] method gives you a place to clean up from your test case.
• In this case just set classToTestRef equal to null so the instance is available for garbage collection
• In more complicated tests it is often crucial to remove listeners, etc. in this way. In our case TwitterHelper is already removing the listeners so we don’t need to do that, but many other times you will.
[Before]
public function setMeUp():void
{
classToTestRef = new TwitterHelper();
}
[After]
public function tearMeDown():void
{
classToTestRef = null;
}
See the complete test code below:
package flexUnitTests
{
import flash.events.Event;
import flexunit.framework.Assert;
import org.flexunit.async.Async;
import utils.TwitterHelper;
import utils.TwitterHelperFailureEvent;
import utils.TwitterHelperSuccessEvent;
public class TwitterHelperTester
{
// Reference declaration for class to test
private var classToTestRef : utils.TwitterHelper;
public function TwitterHelperTester()
{
}
[Before]
public function setMeUp():void
{
classToTestRef = new TwitterHelper();
}
[After]
public function tearMeDown():void
{
classToTestRef = null;
}
[Test(async,timeout="20000")]
public function testRetrieveTweetsBasedOnHashTag():void
{
var EVENT_TYPE:String = TwitterHelperSuccessEvent.RETRIEVE_TWEETS;
classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this, handleAsyncEvnet, 20000 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "http://search.twitter.com/search.json");
}
[Test(async,timeout="20000")]
public function testRetrieveTweetsBasedOnHashTagFail():void
{
var EVENT_TYPE:String = TwitterHelperFailureEvent.SERVICE_FAILURE;
classToTestRef.addEventListener( EVENT_TYPE, Async.asyncHandler( this, handleAsyncFaultEvnet, 20000 ), false, 0, true );
classToTestRef.retrieveTweetsBasedOnHashTag("FlashAndTheCity", "");
}
//--------------------------------------------------------------------------
//
// Asynchronous handlers
//
//--------------------------------------------------------------------------
private function handleAsyncEvnet(event:Event, passThroughData:Object):void
{
Assert.assertEquals( event.type, "retrieveTweets" );
}
private function handleAsyncFaultEvnet(event:Event, passThroughData:Object):void
{
Assert.assertEquals( event.type, "serviceFailure" );
}
}
}
In addition to refactor the tests you should also refactor the actual code. We focus on passing the test and didn’t care that much about the code, however you may find out that the code is too complex and can be simplify by implementing a design pattern, or just adding some small modification. For instance, I can add metadata so when you instantiate the class and add event listeners in MXML component you will get the event type available automatically. Add the code below to the TwitterHelper class:
/** * Success custom event * * @eventType utils.TwitterHelperSuccessEvent.RETRIEVE_TWEETS */ [Event(name="retrieveTweets", type="utils.TwitterHelperSuccessEvent")] /** * Failure custome event * * @eventType utils.TwitterHelperFailureEvent.SERVICE_FAILURE */ [Event(name="serviceFailure", type="utils.TwitterHelperFailureEvent")]
You can see the complete code for the TwitterHelper class below:
package utils
{
import com.adobe.serialization.json.JSON;
import flash.events.EventDispatcher;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
/**
* Success custom event
*
* @eventType utils.TwitterHelperSuccessEvent.RETRIEVE_TWEETS
*/
[Event(name="retrieveTweets", type="utils.TwitterHelperSuccessEvent")]
/**
* Failure custome event
*
* @eventType utils.TwitterHelperFailureEvent.SERVICE_FAILURE
*/
[Event(name="serviceFailure", type="utils.TwitterHelperFailureEvent")]
public class TwitterHelper extends EventDispatcher
{
/**
* Holds the service class
*/
private var service:HTTPService;
//--------------------------------------------------------------------------
//
// Default Constructor
//
//--------------------------------------------------------------------------
public function TwitterHelper()
{
// implement
}
/**
* Method to send a request to retrieve all the tweet with a HashTag
* @param hashTag defined hashtag to search
* @url the twitter API url
*
*/
public function retrieveTweetsBasedOnHashTag( hashTag:String, url:String ):void
{
service = new HTTPService();
service.url = url;
service.resultFormat = "text";
service.addEventListener(ResultEvent.RESULT, onResults);
service.addEventListener(FaultEvent.FAULT, onFault);
var object:Object = new Object();
object.q = hashTag;
service.send( object );
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* Method to handle the result of a request to retrieve all the list
* @param event
*
*/
private function onResults(event:ResultEvent):void
{
service.removeEventListener(ResultEvent.RESULT, onResults);
service.removeEventListener(FaultEvent.FAULT, onFault);
var rawData:String = String( event.result );
var object:Object = JSON.decode( rawData );
var results:Array = object.results as Array;
var collection:Vector.<TweetVO> = new Vector.<TweetVO>;
results.forEach( function callback(item:*, index:int, array:Array):void {
var tweet:TweetVO = new TweetVO( item.from_user, item.from_user_id, item.geo, item.id,
item.profile_image_url, item.source, item.text, item.to_user, item.to_user_id );
collection.push( tweet );
});
// dispatch an event that holds the results
this.dispatchEvent( new TwitterHelperSuccessEvent( collection ) );
}
/**
* Holds the fault method in case the service failed
*
* @param event
*
*/
private function onFault(event:FaultEvent):void
{
service.removeEventListener(ResultEvent.RESULT, onResults);
service.removeEventListener(FaultEvent.FAULT, onFault);
this.dispatchEvent( new TwitterHelperFailureEvent( event.fault.message ) );
}
}
}
Retrieve tweets every few seconds User Story
The second user story objective is to call the same method we just created every X seconds so we can keep retrieving tags that contain FlashAndTheCity keyword from Twitter, see Figure 15.

Figure 15: Retrieve tweets every few seconds User Story
This type of logic doesn’t have to be included in the utility class we created since it’s a specific implementation of the class and I prefer to keep the class generic so it can be re-used.
In the application I am creating I decided to avoid using any micro-architecture framework since the application is simple in nature and I am the only developer working on the application so no need to add complexity.
The architecture I prefer to implement is to separate the API from the implementation and handle this logic in the actual implementation of the class rather than the utility class. To achieve that I will create a design patter that will help me to separate the view and logic. It’s highly recommended to use some sort of presentation model (also known as code behind), so you can easily separate the data and logic from the view, state and transitions (animations).
This type of separation will allow you to better test your code. In my case I decided to implement the Passive Presentation Model, but there are many other ways to achieve the same goal. I am not going to go into too much detail, but feel free to visit the following link to find out more:
http://blogs.adobe.com/paulw/archives/2007/11/presentation_pa_6.html#more
Since we are using a different class for the implementation this user story I would create a new test case for this class. If you recall last time we created the class before the test case, this time I will create the Test Case and once I get compile time error I will add the class.
Create a new Test Case and fill in the information below, see Figure 16.
• Use TweetListPresenterTester as the name
• New FlexUnit 4 test
• Select Finish

Figure 16: Create TweetListPresenterTester Test Case Class
Make sure to add a reference of the Test Case to the Test Suite, otherwise it wont run the test.
package flexUnitTests
{
[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class CompanionTestSuite
{
public var twitterHelperTester:TwitterHelperTester;
public var tweetListPresenterTester:TweetListPresenterTester;
}
}
The unit test will include a reference to the presenter and will test the method that retrieve tweets every few seconds.
package flexUnitTests
{
import flexunit.framework.Assert;
import org.flexunit.async.Async;
import utils.TwitterHelperSuccessEvent;
public class TweetListPresenterTester
{
// Reference declaration for class to test
private var classToTestRef : presenter.TweetListPresenter;
public function TweetListPresenterTester()
{
classToTestRef = new TweetListPresenter();
}
[Test(async,timeout="2000")]
public function testRetrieveTweetsEveryFewSeconds():void
{
classToTestRef.twitterHelper.addEventListener( TwitterHelperSuccessEvent.RETRIEVE_TWEETS, Async.asyncHandler( this, handleAsyncTweetSuccessEvnet, 2000 ), false, 0, true );
classToTestRef.retrieveTweetsEveryFewSeconds( 4 );
}
//--------------------------------------------------------------------------
//
// Asynchronous handlers
//
//--------------------------------------------------------------------------
private function handleAsyncTweetSuccessEvnet(event:TwitterHelperSuccessEvent, passThroughData:Object):void
{
Assert.assertTrue( event.collection.length > 0 );
}
}
}
After you compile the application you will get the following compile time errors:
1. Type was not found or was not a compile-time constant: TweetListPresenter
2. Call to a possibly undefined method retrieveTweetsEveryFewSeconds through a reference with static type presenter:TweetListPresenter
3. Access of possibly undefined property twitterHelper through a reference with static type presenter:TweetListPresenter.
Once again, these compile time errors are a good thing, so our first task is to solve these errors by creating the TweetListPresenter class, method retrieveTweetsEveryFewSeconds and property twitterHelper. The test will start the method that should create a timer and call the service every four seconds. Once the service is called we should retrieve some data to indicate that the test succeeded.
I have created TweetListPresenter class and added the method and property so the compile time errors will be fixed see code below:
package presenter
{
import utils.TwitterHelper;
public class TweetListPresenter
{
public var twitterHelper:TwitterHelper;
public function TweetListPresenter()
{
twitterHelper = new TwitterHelper();
}
public function retrieveTweetsEveryFewSeconds( seconds:int ):void
{
// implement
}
}
}
Run the test and you will see that it fails since we haven’t created the logic yet, see Run FlexUnit Tests wizard below.


Figure 17: Run FlexUnit Tests wizard to test testRetriveTweetsEveryFewSeconds method

Close the results view and observe the results, see Figure 18.
Figure 18: Results view shows testRetriveTweetsEveryFewSeconds have failed
As I explained the utility class we created is a wrapper for the Twitter API and doesn’t include any implementation logic, with that said by creating a presenter we can separate the view from the logic and better test the implementation logic.
The approach is to create a passive presenter that controls the view components passively. Create the application entry point and paste the following code, which will add a view to the application and pass that view to the presenter so it can adjust the view properties, such as adding a list of tweets to a datagrid:
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:view="view.*"
creationComplete="creationCompleteHandler()">
<fx:Script>
<![CDATA[
import presenter.TweetListPresenter;
private var tweetListPresenter : TweetListPresenter;
protected function creationCompleteHandler():void
{
tweetListPresenter = new TweetListPresenter( tweetListView );
}
]]>
</fx:Script>
<view:TweetListView id="tweetListView" />
</s:WindowedApplication>
Notice that we are passing an instance of the view so we can control the view based on the logic in the presenter class. Next adjust the constructor in the presenter class:
// Corresponding view
private var _tweetListView : TweetListView;
public function TweetListPresenter( tweetListView:TweetListView )
{
_tweetListView = tweetListView;
twitterHelper = new TwitterHelper();
}
Additionally, create an empty view and name it TweetListView.mxml that we will be using to place the view components and sub-components once we are ready:
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" width="400" height="300"> </s:Group>
At this point we can compile the application and see an empty screen since we didn’t added any view components.
Write code
We are now ready to write the code needed for our test to pass.
package presenter
{
import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.collections.ArrayCollection;
import utils.TweetVO;
import utils.TwitterHelper;
import utils.TwitterHelperFailureEvent;
import utils.TwitterHelperSuccessEvent;
import view.TweetListView;
public class TweetListPresenter
{
/**
* Corresponding view
*/
private var _tweetListView : TweetListView;
/**
* Twitter helper utility class instance
*/
public var twitterHelper:TwitterHelper;
/**
* Holds a timer so we will be able to update list
*/
public var timer:Timer;
//--------------------------------------------------------------------------
//
// Default Constructor
//
//--------------------------------------------------------------------------
public function TweetListPresenter( tweetListView:TweetListView )
{
_tweetListView = tweetListView;
twitterHelper = new TwitterHelper();
twitterHelper.addEventListener( TwitterHelperSuccessEvent.RETRIEVE_TWEETS, onRetrieveTweets );
twitterHelper.addEventListener( TwitterHelperFailureEvent.SERVICE_FAILURE, onFaultRequest );
}
/**
* Method to go and retireve tweets every defined number of seconds
*
* @param seconds
*
*/
public function retrieveTweetsEveryFewSeconds( seconds:int ):void
{
timer = new Timer( seconds*1000, 100000 );
timer.addEventListener(TimerEvent.TIMER, onTimerHandler);
timer.start();
}
//--------------------------------------------------------------------------
//
// Handlers
//
//--------------------------------------------------------------------------
/**
* Method to handle a timer event
*
* @param event
*
*/
private function onTimerHandler( event:TimerEvent ):void
{
twitterHelper.retrieveTweetsBasedOnHashTag( "FlashAndTheCity", "http://search.twitter.com/search.json" );
}
/**
* Handler for results
*
* @param event
*
*/
private function onRetrieveTweets( event:TwitterHelperSuccessEvent ):void
{
var dataProvider:Array = new Array();
event.collection.forEach( function callback(item:TweetVO, index:int, vector:Vector.<TweetVO>):void {
dataProvider.push( item );
} );
this._tweetListView.dataGrid.dataProvider = dataProvider;
}
/**
* Handler for fault
*
* @param event
*
*/
private function onFaultRequest( event:TwitterHelperFailureEvent ):void
{
}
}
}
The code have a method called retrieveTweetsEveryFewSeconds, which starts a timer and allow us to call twitterHelper.retrieveTweetsBasedOnHashTag every few seconds. Add a DataGrid to the TweetListView.mxml so we can show the results;
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" width="400" height="300"> <mx:DataGrid id="dataGrid" width="500" height="400" /> </s:Group>
Run the test and observe the passed test in the result view, see Figure 19:

Figure 19: Results View window showing testRetriveTweetsEveryFewSeconds Method passed
At this point you can also run the application and see the DataGrid shows results every four seconds, see Figure 20.

Figure 20: Companion application shows twitter results in a DataGrid
Refactor
I have done some additional refactoring to the code and you can download the complete project from here: Companion.fxp
Conclusion
This article covered Test Driven Development in Flex projects. We first defined the project we are creating by defining our user stories and than created the tests using FlexUnit 4. We followed the TDD process without suger coat the process, but showing a real realistic example you can follow and allow you to understand the process of using TDD.
After learning how to create FlexUnit test suites and test cases as well as follow the process, I hope you are inspired to use TDD on your mobile, web, and desktop Flash applications, and write better, more scalable, and more reusable code.
You can download the doc, preso and project files from here:
http://eladelrom-preso.googlecode.com/files/TDD.zip
Cheers





















