Archive for April, 2008
Running Your Test Cases Automatically
A while ago I wrote a tutorial on Unit Testing and Test Driven Development for Adobe, and earlier this week somebody (and I've completely forgotten who, sorry!) asked me to clarify a point in the article, where I alluded to a way of automatically running all test methods which begin with the word "test". I thought I'd posted about it ages ago, but looks like I was mistaken [EDIT: nope - here it is!].
There are two changes needed, and both are located in the same file (AccountTest.as)
1. In the constructor, AccountTest(methodName:String) should be given a default value of null, and therefore becomes AccountTest(methodName:String = null)
2. Rather than adding tests using addTest, we add a testSuite using addtestSuite. We no longer need to pass in the string name of the method.
Here is the relevant part of the class, with the old code commented out:
-
public class AccountTest extends TestCase
-
{
-
//Give the methodName param a default value of null
-
public function AccountTest(methodName:String = null)
-
{
-
super(methodName);
-
}
-
-
public static function suite():TestSuite
-
{
-
var accountTS:TestSuite = new TestSuite();
-
accountTS.addTestSuite(AccountTest); //*- this is new
-
-
//This is too much like hard work:
-
//accountTS.addTest(new AccountTest("testNew"));
-
//accountTS.addTest(new AccountTest("testCreditWithNullValue"));
-
//accountTS.addTest(new AccountTest("testCreditWithRealValue"));
-
//accountTS.addTest(new AccountTest("testCreditWithRealValueTothreeDecimalPlaces"));
-
-
return accountTS;
-
}
-
-
//OTHER METHODS HERE.....
-
}
Now when you run the project, all your methods within this class which begin with the word 'test' will run automatically. Much better eh :]
No comments
2 Random Flex Tips
When I end up helping someone with Flex, it nearly always gives me an idea for a new tip post :]
Creating A Nested Folder Structure In FlexBuilder
I've seen my fair share of people create their folder structures the long way round, and not just those who are new to Flex, so here's a tip... right-click on your project -> new -> folder -> [type the folder(s) you want to create]

No, The Combo Prompt Isn't Lost
I don't know if this is a commonly held [mis]belief, but twice I have heard people say that if you have a combo with promp-text specified, and then select an item from the combo, the prompt will be lost ... forever! No it's not. To display it again simply reset the selectedIndex to -1 (as it says in the docs)
//initial combo setup
myCombo.prompt = "Select an item...";
myCombo.dataProvider = myDataProviderObject ;
... and then later on ...
//reset the combo to display the prompt
myCombo.selectedIndex = -1;
trace("yay");
2 comments
More Component LifeCycle Stuff (null error avoidance)
In the last post I wrote a little about the component life cycle and why it is useful to know about it even if you are not creating advanced components. Here is a similar situation you may find yourself in when extending components, which would result in an error being thrown ...
The HeaderBar Component
Let's say you have created your own simple "HeaderBar.mxml" component - all this does is extend Canvas and add a Label to display some text.
The label has an instance name of headerTextDisplay
[as my current WordPress plugin struggles with mxml, I'll just show the ActionScript code]
The script in your HeaderBar.mxml file would look something like this:
-
//Here we try to retrieve/assign the text directly to the Label instance
-
public function get text():String
-
{
-
return headerTextDisplay.text;
-
}
-
-
public function set text(value:String):void
-
{
-
headerTextDisplay.text = value;
-
}
In your main Application file you instantiate a copy of your HeaderBar class through ActionScript ...
Here is what the script in your main.mxml file may look like:
-
private function onCreationComplete():void
-
{
-
var header:HeaderBar = new HeaderBar();
-
header.text = "Hello World!";
-
addChild(header);
-
}
Now that seems pretty reasonable to me, however, the call to set the text would result in the following error being thrown: Error #1009: Cannot access a property or method of a null object reference
The reason for this error is simple. At the time you try to assign the text, the Label (which is a child of your HeaderBar component) has not been created. If you read back through my previous post you will understand why - at this point we've not added our component to the display list, and so the component instantiation has only got so far. If we instead decide to add the child first and then assign the text, everything should work! However, when we create components they should not be as brittle as that. We want to be able to declare properties before we add the component to the display list. This is how all the inbuilt components work, and ours should follow suit.
Failure Is Not An Option
So how do we avoid this error and still allow the user of our component to set properties before adding it to a display list?
First of all we do not assign our property values directly to our component's children. Instead we store them in private variables until we are ready (there are other reasons for doing this, but they are beyond the scope of this basic tutorial - if you want to read more, there is an excellent chapter in Programming Flex 2). We also use boolean flags to "mark the properties as being dirty" - this is optional and in fact not needed at all for such a simple component, but as your component grows in size it will prevent code from being run unnecessarily, and is good practise so I'll show it in the example.
A Better Component
The code in our main.mxml file stays the same. It is only our HeaderBar.mxml file that changes. I'll show the code and then explain it in more detail:
-
private var _text:String;
-
private var _textDirty:Boolean = false;
-
-
//In our setter we assign the text to a private variable. We
-
//then tell the framework that one or more
-
//properties are invalid.
-
public function get text():String
-
{
-
return _text;
-
}
-
-
public function set text(value:String):void
-
{
-
_text = value;
-
_textDirty = true;
-
invalidateProperties(); //calls commitProperties
-
}
-
-
override protected function commitProperties():void
-
{
-
super.commitProperties();
-
if(_textDirty)
-
{
-
headerTextDisplay.text = text;
-
_textDirty = false;
-
}
-
}
So the fist thing we do is declare a private variable to hold our text value, and another variable which is a boolean flag. When the setter is called, the value gets assigned to the private _text variable, and not directly to the Label component. We also set the value of _textDirty to be true and call invalidateProperties().
Ignoring the _textDirty property for just a second, what the invalidateProperties() call does is to alert Flex to the fact that at least one of the properties has changed ... and therefore the values being used currently are invalid. This will cause Flex to re-assess the property values when it is next convenient, and it does that by calling a method called commitProperties() - you should never call commitProperties directly (again, this is beyond the scope of this post, but check out the recommended book or the Flex documentation for more info).
The _textDirty flag is for our own use - we want to mark which property or properties have changed since the properties were last assessed by Flex, and therefore we know which ones need updating. When commitProperties() is called by the Flex framework, we could update all properties, but by using a flag we can ensure we only update the ones which have changed - which is less processor intensive when your component has multiple properties and not all need to be updated.
So, without getting too heavily in to the component lifecycle, what we are doing is first saying "hey, our text property is the one that has changed", and then telling Flex to reassess all properties.
Committed
In the component lifecycle, the validation of properties does not occur until after the component's children have been created, and this is why you can be assured that when commitProperties() is called by the framework, all the child components, such as our Label, will have been fully instantiated. This is why we do the assigning of the text value to the Label component within the commitProperties method.
HeaderBar is a subclass of Canvas, so we need to override the existing commitProperties() method which belongs to the superclass. We do this using the override keyword and call super.commitProperties() to ensure that the superclass's method gets run first and does all the validation it needs to do for the properties of Canvas. Then we can add in our additional 'stuff'.
We only want to update properties which have changed, and this is where our boolean flag comes in to play - if it is 'true' then that property needs updating. In our case it is true for the text property, so we assign our updated text value to the ".text" property of the headerTextDisplay Label instance. We know that by this point in the lifecycle, the Label instance will exist, so we will not get that null object error. Finally we reset our flag to be false.
Finally
Here I've used a simplified example to try and give you an insight in to how you can make your components more sturdy, while explaining a little more about the component life-cycle. To some it may seem like too much effort, especially when you can just ensure you add your components to the display list before assigning values, but you will almost certainly come across situations down the line where this will not suit your needs, and so understanding more about how the Flex team build their components will help you produce more reusable items.
7 comments