EladElrom.com

Deep Dive Into Technology

Improve Flash Catalyst Performance

@polyGeek reminded me today (see blog post here) about increasing the memory size allocated to Eclipse and made me wonder if I can do the same thing to FlashCatalyst.

You probably noticed that Flash Catalyst is often slow. As you may know Flash Catalyst is based on Eclipse IDE and just like any Eclipse instance you can improve performance simple by tweaking the heap size and permSize to maximize performance. You should give the VM as much ram as you can and set the min and max values (the same) to avoid resizing of your memory.

On PC change “Adobe Flash Catalyst CS5.ini” located here
C:Program FilesAdobeAdobe Flash Catalyst CS5

On MAC: Under /Applications/Adobe Flash Catalyst CS5 Adobe Flash Catalyst , select Adobe Flash Catalyst CS5.app and right click the app > select “Show Package Contents”, and then traversed to find the location of the “Adobe Flash Catalyst CS5.ini” file.

Flash Catalyst comes with larger memory allocation than Flash Builder, see below:

-clean
-vmargs
-Xdock:icon=../Resources/fc_app.icns
-Xdock:name=Flash Catalyst
-XstartOnFirstThread
-Xms512m
-Xmx512m
-XX:MaxPermSize=256m
-XX:PermSize=64m
-Dorg.eclipse.swt.internal.carbon.smallFonts
-Dorg.eclipse.swt.internal.carbon.noFocusRing

You can increase the Xms and MaxPermSize to improve performance.
I have 4GB RAM on my MBP machine and changed the heap to 1024m and a permSize to 512m.

-Xms1024m
-Xmx1024m
-XX:MaxPermSize=512m

I notice significant improvement. Cheers :)

FXGStringConverter – converts FXG text string to component during runtime

There are times were you need to take an FXG (Flash XML Graphic) from Photoshop, Illustrator or Flash Catalyst and load it during runtime. FXG is usually handled by the MXMLC which turns the declarative language into ActionScript code. The utility class will do just that and convert the text string into ActionScript code which can than be added to the display object or manipulated during runtime. Take a look at a simple implementation which allow the user to insert text string and it will turn it into a group component:

httpv://www.youtube.com/watch?v=kE7P_WFqIP8

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
	xmlns:s="library://ns.adobe.com/flex/spark"
	xmlns:mx="library://ns.adobe.com/flex/mx"
	minWidth="955" minHeight="600">

	<fx:Script>
		<![CDATA[
			import com.elad.framework.utils.fxgconverter.FXGStringConverter;

			protected function button_clickHandler(event:MouseEvent):void
			{
				var comp:Group = FXGStringConverter.convertFXGStringToComponent( textArea.text, true );
				group.addElement( comp );
			}

		]]>
	</fx:Script>

	<s:TextArea id="textArea" width="300" height="200" />
	<s:Button id="button" x="14" y="214" label="Submit" click="button_clickHandler(event)"/>
	<s:Group id="group" width="500" height="500" x="0" y="300" />

</s:Application>

screen-shot-2010-03-30-at-92633-am

Although I tested it on all the code that I needed, keep in mind that the code is still in alpha and is not fully tested, so I am sure there may be cases where it will fail. Also group your FXG code since I haven’t tested it fully with all types of code. See FXG sample below:

<s:Group id="groupSample1">
     <s:Ellipse id="ellipse" width="30" height="30">
          <s:fill>
               <s:SolidColor color="0x000000"></s:SolidColor>
          </s:fill>
      </s:Ellipse>
</s:Group>

The code is published as open source and hosted under my private library:
http://github.com/EladElrom/eladlib

Tip: calculate properties such as position and measurements for Flex Spark Label component

There are cases where you need to find out position and measurements for Flex Spark Label component. There are many cases where you will find the code useful, such in case you need to calculate the width of a text string in pixels during runtime. Take a look at the following code snippet:

var label:Label = new Label();
label.regenerateStyleCache( false );
var textMetrics:TextLineMetrics = label.measureText( name );
var textWidth:int = textMetrics.width;

textWidth will hold the text width in pixels.

TextLineMetrics is part of the TLF framework and contain information about the text position, measurements etc. See more here:
http://livedocs.adobe.com/labs/textlayout/flash/text/TextLineMetrics.html

label.regenerateStyleCache(false); is used to ensure that the label component updated the metrics since many times commit properties or invalidate properties wouldn’t do the trick.

There are cases where you need to truncate (remove text and add dot dot dot) the text of a Spark Label once the text exceed a certain width. To do that you can add the following command:

import spark.components.supportClasses.TextBase;
TextBase.mx_internal::truncationIndicatorResource = "...";

Make sure you also add maxDisplayedLines="1" to the label component.

Tutorial – Drag And Drop an FXG element

One of the most used visual development in Flex is drag and drop functionality I am using Flex 4 SDK since early iteration and really enjoyed the new Spark component and FXG (Flash XML Graphic) architecture. I was asked last week by one of my developer to help him understand how to work with FXG code and apply drag and drop functionality, so I created a quick POC (Proof Of Concept) and decided to share it in case someone have a similar application and running into difficulties. Before we get started I want to point out the the code is written very quickly and can be improved. I only wanted to give the basics and you can take it from here.

Drag and drop operation consists of three steps:

  • Initiation
  • Dragging
  • Dropping

To drag FXG element is similar to how you would create drag and drop in Flex3, since the FXG can be wrapped in a Group which extends GroupBase (which than extends UIComponent), however there are few changes in terms of wrapping the FXG as an object that the DragManager recognize.

Let’s take a look.

We set two components: a List to hold the FXG components and a Group component to hold the drop items, see below:

	<!-- source -->
	<s:List id="list" mouseDown="mouseDownHandler(event)"
			x="0" y="0"
			skinClass="components.DataList"
			width="169" height="200"/>

	<!-- dest -->
	<s:Group id="group"
			 width="200" height="200"
			 x="190" y="0"
			 dragEnter="dragEnterHandler(event);"
			 dragDrop="dragDropHandler(event);">

		<s:Rect top="0" left="0" right="0" bottom="0">
			<s:fill>
				<s:SolidColor color="0xCCCCCC" />
			</s:fill>
		</s:Rect>

	</s:Group>

Once the user click mouse down on an item in the list the event handler start tracking the mouse move event and will call the startDragItem method:

// holds the selected index
private var selectedIndex:int;

public function mouseDownHandler( event:MouseEvent ):void
{
	selectedIndex = (event.currentTarget as List).selectedIndex;
	this.addEventListener(MouseEvent.MOUSE_MOVE, startDragItem );
}

The startDragItem method will pick the item that was selected and cast it as a ComponentVO and set the following:

  • drag source
  • drag initator
  • set the image source
  • set the data

Once we create all that information that is needed you can set the DragManager as follow:
DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );

See code below:

private function startDragItem( event:MouseEvent ):void
{
	var selectedItem:ComponentVO = collection.getItemAt( selectedIndex ) as ComponentVO;

	// drag source
	var dragSource:DragSource = new DragSource();

	// drag initator
	var dragInitiator:Group = selectedItem.fxg;

	// create an image
	var bitmapData:BitmapData = getBitmapData( selectedItem.fxg );
	var bitmap:Bitmap = new Bitmap( bitmapData );

	// set the image source
	var dragProxy:Image = new Image();
	dragProxy.source = bitmap;

	// set the data
	dragSource.addData( selectedItem, "ComponentVO" );

	DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );
}

// retrieve the bitmap data of a component
private function getBitmapData( target:UIComponent ):BitmapData
{
	var bitmapData:BitmapData = new BitmapData( target.width, target.height );
	var matrix:Matrix = new Matrix();
	bitmapData.draw( target, matrix );

	return bitmapData;
}

The destination have event handlers to trace drag enter and drag drop events:
dragEnter=”dragEnterHandler(event);” dragDrop=”dragDropHandler(event);”

The handlers will allow adding the item to the destination component and add the actual FXG component:

// drop item
private function dragDropHandler( event:DragEvent ):void
{
	this.removeEventListener( MouseEvent.MOUSE_MOVE, startDragItem );

	var selectedItem:ComponentVO = event.dragSource.dataForFormat('ComponentVO') as ComponentVO;
	selectedItem.fxg.x = 0;
	selectedItem.fxg.y = 0;
	this.group.addElement( selectedItem.fxg );
}

private function dragEnterHandler( event:DragEvent ):void
{
	var dropTarget:Group = event.currentTarget as Group;

	if (event.dragSource.hasFormat('ComponentVO'))
	{
		DragManager.acceptDragDrop(dropTarget);
	}
}

Last part is to create static FXG component we can use. You can load the object or runtime or pass it from a different class or service, this example is just a POC so I kept it simple but you get the idea. Once the creationCompleteHandler is called the collection will be filled with the two objects:

// handles creation complete
protected function creationCompleteHandler(event:FlexEvent):void
{
	collection = new ArrayCollection();

	collection.addItem( new ComponentVO( "Item1", groupSample1 ) );
	collection.addItem( new ComponentVO( "Item2", groupSample2 ) );

	list.dataProvider = collection;
}

The sample FXG code will look as follow:

	<!-- Holds a sample FXG code -->
	<s:Group id="groupSample1">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x000000">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>
	<s:Group id="groupSample2">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x00FF00">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>

Complete code is listed below:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="955" minHeight="600"
			   creationComplete="creationCompleteHandler(event)">

	<fx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.controls.Image;
			import mx.core.DragSource;
			import mx.core.UIComponent;
			import mx.events.DragEvent;
			import mx.events.FlexEvent;
			import mx.managers.DragManager;

			import vo.ComponentVO;

			// holds the collection
			private var collection:ArrayCollection;

			// holds the selected index
			private var selectedIndex:int;

			public function mouseDownHandler( event:MouseEvent ):void
			{
				selectedIndex = (event.currentTarget as List).selectedIndex;
				this.addEventListener(MouseEvent.MOUSE_MOVE, startDragItem );
			}

			// handles creation complete
			protected function creationCompleteHandler(event:FlexEvent):void
			{
				collection = new ArrayCollection();

				collection.addItem( new ComponentVO( "Item1", groupSample1 ) );
				collection.addItem( new ComponentVO( "Item2", groupSample2 ) );

				list.dataProvider = collection;
			}

			private function startDragItem( event:MouseEvent ):void
			{
				var selectedItem:ComponentVO = collection.getItemAt( selectedIndex ) as ComponentVO;

				// drag source
				var dragSource:DragSource = new DragSource();

				// drag initator
				var dragInitiator:Group = selectedItem.fxg;

				// create an image
				var bitmapData:BitmapData = getBitmapData( selectedItem.fxg );
				var bitmap:Bitmap = new Bitmap( bitmapData );

				// set the image source
				var dragProxy:Image = new Image();
				dragProxy.source = bitmap;

				// set the data
				dragSource.addData( selectedItem, "ComponentVO" );

				DragManager.doDrag( dragInitiator, dragSource, event, dragProxy );
			}

			// retrieve the bitmap data of a component
			private function getBitmapData( target:UIComponent ):BitmapData
			{
				var bitmapData:BitmapData = new BitmapData( target.width, target.height );
				var matrix:Matrix = new Matrix();
				bitmapData.draw( target, matrix );

				return bitmapData;
			}

			// drop item
			private function dragDropHandler( event:DragEvent ):void
			{
				this.removeEventListener( MouseEvent.MOUSE_MOVE, startDragItem );

				var selectedItem:ComponentVO = event.dragSource.dataForFormat('ComponentVO') as ComponentVO;
				selectedItem.fxg.x = 0;
				selectedItem.fxg.y = 0;
				this.group.addElement( selectedItem.fxg );
			}

			private function dragEnterHandler( event:DragEvent ):void
			{
				var dropTarget:Group = event.currentTarget as Group;

				if (event.dragSource.hasFormat('ComponentVO'))
				{
					DragManager.acceptDragDrop(dropTarget);
				}
			}

		]]>
	</fx:Script>

	<!-- Holds a sample FXG code -->
	<s:Group id="groupSample1">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x000000">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>
	<s:Group id="groupSample2">
		<s:Ellipse width="30" height="30">
			<s:fill>
				<s:SolidColor color="0x00FF00">
				</s:SolidColor>
			</s:fill>
		</s:Ellipse>
	</s:Group>

	<!-- source -->
	<s:List id="list" mouseDown="mouseDownHandler(event)"
			x="0" y="0"
			skinClass="components.DataList"
			width="169" height="200"/>

	<!-- dest -->
	<s:Group id="group"
			 width="200" height="200"
			 x="190" y="0"
			 dragEnter="dragEnterHandler(event);"
			 dragDrop="dragDropHandler(event);">

		<s:Rect top="0" left="0" right="0" bottom="0">
			<s:fill>
				<s:SolidColor color="0xCCCCCC" />
			</s:fill>
		</s:Rect>

	</s:Group>

</s:Application>

screen-shot-2010-03-20-at-25531-pm

Download the complete FXP code from here:
http://elromdesign-example-codes.googlecode.com/files/DragDropFXG.fxp

MIX10 recap from a Flash/Flex developer standpoint

I am sitting at the airport waiting for my flight to leave back to New York City and trying to gather my thoughts about MIX 2010. This was the first time I was attending Microsoft MIX conference and as someone that spent the last few years focusing solely on Adobe’s technologies, this is definitely out of my comfort zone. I have done C-Sharp/ C++ programming years ago and used Visual Studio 2002/2003 but haven’t kept in touch with Microsoft development tools since then. I had a great time hanging out with the Flash community friends such as @TheFlashBum @adamflater @jefftapper @jesterxl, @Rhall, @__Ted__ , as well as my new Microsoft friends such @adkinn, @brianjo and @thedavedev.

26

It’s definitely refreshing to be involved and know where other vendors such as Microsoft are heading and it actually helped me better understand Adobe’s road map better. It appears that Microsoft is focusing on three main areas in regards to the Web:

  • Mobile
  • RIA
  • Browser

Microsoft is known for sitting on the fence and waiting to see what works and then to launch an assault using their 8,000 engineers’ brainpower. Microsoft advancement is an attempt to ensure Microsoft has a solution for the technology advancement from Apple, Adobe and Mozilla and provides their developers the ability to stay with Microsoft without wondering around to other vendors. It’s like going to a 5-star resort where you get the hair dresser, the beach, restaurants, jewelry stores, a pool and maybe even a golf course, so you have no reason to leave the resort, however, staying at the resort you don’t get the culture and some of your culinary experiences are artificial.

You need to be adventures and explore, which is something the Flash community is not afraid of. Many Flash professionals have embraced other technologies such as open source projects GIT or other 3rd party vendors such PHP, Objective-C and others. It’s not rare to hear that someone is involved in Flash and Unity3d, however, from talking to others at MIX conference, I rarely heard many talking about any other technologies other then MS, and I asked.

Additionally, since MS is sitting on the fence and waiting to see what’s the next big thing, they are paying a price and everything that I have seen isn’t that impressive in terms of showing off new innovative technologies. With that said, I was extremely impresses by the speed and efficiency of Microsoft to reach what took other companies took years to achieve and how they can partner with other large corporations. For instance:

  • Microsoft claims that they achieved 60% penetration with Silverlight plugin. Even if the numbers are 55% that’s pretty impressive considering the fact that other plug-ins took years to achieve that type of penetration.
  • Microsoft Expression Blend is the equivalent of Flash Catalyst. The product was in the works since 2006 and first released in 2007 and the latest built is pretty impressive considering that MS does not have a long background with design and the tool can even allow importing illustrator, Photoshop and CS4 FXG code.

Windows Phone 7

The biggest announcement was the release of Windows Phone 7 later this year. Let’s look back for a second. In 2004, Windows Mobile took about 23% of worldwide smartphone sales, however, by 2009, it’s shares dropped to 7.9% (according to Gartner). The latest version of Windows Phone 7, codenamed “Photon” is Microsoft’s attempt to increase market share.

Microsoft is going to dictate the hardware requirements and require the OEMs (Original Equipment Manufacturer) to include 3 Hardware buttons (Back, Search and WinKey) as well as other hardware requirements such as Touch Displays with 4 sensor points, A-GPS, Accelerometer, Compass, DX9-capable GPU, Proximity and Light Sensors, 256MB Flash RAM and 8GB Storage Memory, HQ camera with Flash and a camera button.

Keyboard and screen sizes of 800×480 or 480×320 are optional but it lacks some basic features such as copy-paste. The latest phone is MS attempts to move forward and be able to compete with Apple and Google. In terms of software, Mobile Phone 7 will include Office, Outlook, IE 7.5, XBOX Live, Social Networking and others. The feature that impressed me the most was the physics API that is used in XBOX and is available for Windows Mobile and SL.

In terms of the business model it is similar to how Microsoft sells Windows OS. Microsoft will make the software for Windows Phones, and OEMs pay Microsoft a license fee for each device they ship. Developers can monetize by selling apps on the Windows Phone Marketplace.

Microsoft is taking a similar approach to Apple’s walled garden and requires certifying apps before they are added to the app store. Developers can offer free apps, such as ad-supported apps, can sell apps by downloading like the iPhone app model, and a “freemium” model in which they could offer free-trial app with an option to buy an upgrade. Developers would get to keep 70% while Microsoft keeps 30%.

From what I have seen so far the device has a while to go before it can really compete with the iPhone. I find it surprising that Apple announced the iPhone in January 2007 and since then they haven’t added any major innovations, in my opinion. At the same time I haven’t seen one Smartphone that can truly provide a GUI experience that is as superior as the iPhone, not even the Droid. I believe that Microsoft needs to start taking some risks and instead of doing “catch up”, provide real software innovations, for instance: context awareness. It would be neat if our Smartphone can recognize that we are at the movie theater based on the GPS and turn the ringer off or recognize that we are sleeping based on the accelerometer is at a horizontal position for a while and go into an hibernation mode.

During the conference I was asking by some MS executives whether the software will include Flash Player 10.1 or at least Flash Lite 3 but I couldn’t get a straight answer, not even off the record. Historically, MS always supported Flash Lite even when they had to purchase the license (prior to the Open Screen Project) but I suspect that it had to do with the underlining OS. During the Keynote, MS pointed out that the device will support the complete full version of SL except for certain graphics APIs so the device is surely capable of deploying FP10.1. But now that MS is competing with Adobe directly, I wouldn’t be surprised if we wont see FP in first release.

Internet Explorer 9

The other big news was IE9. MS has decided not to embrace Webkit and continue their own development. In fact, the new IE9 supports CSS3, HTML5 as well as GPU.

I think that what stood out the most to me is the performance – the new IE9 is faster. How fast? Almost as fast as Safari and appears to handle graphics in some cases better than Chrome or Safari due to the usage of the GPU.

MS engineers appear to be getting very excited during the keynote and other preso by HTML5’s ability to turn few images in 3D space using the GPU. Later I went to a preso by @JasonCWeber about High performance Optimization For Website. Jason pointed out few times stuff like “this type of amazing graphic experience” when he presented the same 3D images floating in space using the GPU. Yes, I agree it’s impressive for HTML but we are in 2010?!

110

Expression Blend

Microsoft Expression Studio is a suite of tools for designing Silverlight application. You can create & import comps from CS4 and using intuitive tool, and add the interactivity, as well as generate code. The tool is impressive and was built from the ground up using .NET but that’s also the caveat – the tool is currently only available for PC. How many designers do you know that use PC? And in fact I asked a few people at MS and they told me that Mac only accounts for 3% of the market, but that’s the 3% you want!

Just as with Flash Catalyst I wonder who is going to be using this tool. Apparently, MS has created a new role called Designer-Developer. Who would be doing this type of development? I attended a great preso by Adam Kinney about Microsoft Expression Blend. MS is attempting to lure Flash designer and developers, however, I don’t see any advantage at this point for Flash developers to start using the tool. MS needs to solve the chicken and the egg problem first. Professionals need work and to be asked to build an application using Silverlight and MS needs to start building a strong portfolio as well as help agencies sell in order to create a case that Silverlight can produce the same type of applications as we see today with Flex. Yes NetFlix is using Silverlight but I haven’t seen any great Website developed with SL. In fact, even SL website needs a facelift.

Additionally, as Flash/Flex developers, we are all used to being the ones converting graphics into code and creating a compelling user experience. Having paintbrushes or the right dancing shoes is useless without having artists capable of creating compelling apps. I believe both Adobe and MS are trying to convince us that UXD people exist. I only know of about 5 UXD people; the rest of the UXD is done by developers.

43

Coming to the MIX conference and seeing MS trying to replicate design and UXD experiences we at the Flash Community are doing for years makes it clear to that RIA is moving into main stream. At this point Microsoft is the underdog since Adobe is doing RIA since Flex 1.5 and even before that with some smart Flash apps so yes Adobe has reasons to worry but as MS will try to catch up, Adobe has an opportunity to innovate and ensure MS is always the underdog. Otherwise, Flex can die. I also noticed that having MS truck heading your way makes some people in the Flash community pretty nervous about their livelihood. There are about a million Flash developers which most of them don’t devote their entire time to RIA or enterprise development, but building banners and touching the technology on rare occasions, so I don’t believe anyone has to worry. At the same time, about 30 mins ago I got a call from a potential side client that told me that his company’s board of directors are leaning toward Silverlight for creating a program that streams video and allows saving the data into the user’s desktop.

Visual Studio 2010, .NET Framework 4.0 and Silverlight 4

Visual Studio finally got the visual update and a developer can work in Designer Mode just like in FlashBuilder, which is a nice feature for Silverlight development. While watching the presentation, I saw some nice features from the IDE that I would die to have in FlashBuilder. But once again, I am not sure if I am quite ready to start working on a PC.

MS is doing what Flash developers are asking for years and teamed up with EBay to open an equivalent of the iTunes app store for developers, which will help developers to monetize and sell Silverlight software. MS knows how to make money and Adobe should take notes. MS is also going to release an open source framework for tracking usage patterns for Silverlight apps running in or out of the browser.

Conclusion

I was very fortunate to be invited to the event by Microsoft and I will be in touch with my new MS friends, however, tomorrow morning I will be still doing Flash unless I have requests from clients for Silverlight applications.

Test Driven Development (TDD) with FlexUnit 4 – Complete Tutorial

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.

11
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.
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).

3
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).

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.

5

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).

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.

71
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.

8

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.

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

10

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.

111

Figure 11: FlexUnit result view in Eclipse

The results view provides several action buttons worth reviewing see Figure 12.
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

13
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.

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.

151
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

16

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.

17

171
Figure 17: Run FlexUnit Tests wizard to test testRetriveTweetsEveryFewSeconds method

18
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:

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.
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 :)