Sunday, 28 February 2010

Running FlexUnit 0.9 tests on a headless *nix server

Using continuous builds to provide a constant overview of the health of your code base is a fairly easy to achieve with Flex projects, by using Ant. Running unit tests should ideally also be a part of this process, because developers often won’t run them before every check in. There is no problem running Flex Unit tests on a Windows server but *nix servers are often used as compile servers for a variety of reasons including cost. Flash Player requires a display to run, and most compile servers in my experience don’t have one. It is in fact very easy to get around this problem, by using a piece of software called XVFB (X Virtual Frame Buffer).

XVFB creates a virtual X server which can be used to satisfy Flash Player’s requirement for a display without having a physical display. This is very useful for running FlexUnit tests as it’s not necessary to see flash player running, just to retrieve the test report at the end. You can read more about the ant task here.

xvfb :21 &
export DISPLAY=:21
#Run your tests here, eg, ant runTestsTarget 

These commands will start the virtual server, set it as the current display and run your tests. You can, of course, just start XVFB once and leave it running rather than continuously starting and stopping it on every run of your tests. This simple tool makes running unit tests on a headless *nix server very simple.

Sunday, 14 February 2010

Optimising Modular Flex Applications using Link Reports

The benefits of creating a modular architecture for large Flex applications has been widely discussed.  When using such an architecture it is important to ensure that your compile process is correctly optimised. The risk with using multiple modules is that classes are compiled into more than one module which results in an unnecessary overhead.  Remember that once the definition for a class has been loaded, any future definitions will be ignored when using a single ApplicationDomain or child ApplicationDomains.  This means that if your main application includes a given classes, a definition for it in any modules you load will never be used. The simple fix for this is to compile all of your modules against the link report of your main application.  This is obviously only suitable if your modules are not going to be loaded by any other application.  The link report is an XML file that describes every class that has been compiled into a SWF, it includes information on the unoptimised and optimised size of every class. To generate a link report you need to apply the following compiler argument: -link-report=myReport.xml.  To compile against a link report and hence optimise your modules, use the following compiler argument: -load-extern=mainAppReport.xml.

The basic optimisation described above may suffice for simple use cases, but sometimes a better understanding of the compiled output is required.  If you compile a main application and multiple modules, analysing the compiled output can help you to understand where optimisation can be achieved.  The following shell script can be run over a directory of link reports, so simply apply the compiler argument given above to your main application and all your modules and run this script (*nix based OS, not Windows).  The output of this is a list of every class compiled into your SWFs and the number of times each class is compiled in.

grep -o "(.*)" *.xml | sed -e 's/\//./g' | sed -e 's/[()]//g' | sort | uniq -c | sort -r

Here's a brief explanation of how it works:  Extract all of the class names (contained between brackets) from the xml link report files, replace the slashes with dots (to give standard fully qualified class names), remove the brackets, sort the list (required by uniq), output a list of unique names with a count and then sort the list in reverse order.

The resulting list should help you to identify classes that are compiled in lots of times.  The libraries that these classes are in will most likely make good candidates for RSLs.  By using the library as an RSL you will load all of the class definition at application startup, which means that that you can externalise these dependancies from all of your modules.  After doing this if you run the script again you should find that these classes are not duplicated.  The first obvious choice for RSLs are the framework, RPC and visualisation RSLs, as these are provided ready to use (see this). It is vital that you externalise any RSLs for SWFs you load, be that compiled style sheets or modules.  To do this use the -external-library-path argument, or in Flex Builder in the project properties set the link type to external.  You can do this with Flex ant as follows:

<mxmlc ...>
   <external-library-path dir="path/to/lib_directory" includes="parlsey.swc"/>
</mxmlc>

It may be a matter of trial and error, but by looking at your link reports you can learn a lot about the classes included in your application and how this affects your file sizes.  Keeping an eye on these statistics over the lifetime of your application is vital so that you can see when things change and understand how to put them right.  A class that is compiled in more than once isn't necessarily a bad thing, you shouldn't expect to see a list of classes where there is only one occurrence of each.  Using RSLs adds a startup overhead of both time and memory.  If you only use 10% of the classes in a library you are undoubtedly better to compile in a few duplicate classes across your modules rather than load the whole library as an RSL at startup.

Sunday, 17 January 2010

Debugging Flex/QTP Issues

Once you have setup a working QTP build, debugging problems can be really tricky. This is mainly because the errors that are reported (if any) aren’t particularly helpful and the documentation is pretty slim. It can also be pretty hard to know how to tackle QTP performance issues. This post will explain some of the techniques I’ve found useful in debugging and solving these issues.

When the Flex/QTP integration encounters an error it traces the problem rather than logging it. This means that to debug problems you will need to connect your QTP enabled application to a debugger in order to see the trace statements. This can make everything run very slowly, so I suggest enabling the logging of trace to a log file which you can examine when you encounter a problem. This can only be done on a debug player, full details can be found here. The second place you can look is QTP’s logs, although I have generally not found them to be very helpful. An explanation of how to enable these logs can be found here.

The most common problem I've encountered while recording or replaying QTP scripts is the object you are trying to identify simply shows up as a “WinObject” or “ActiveX Object”. This happens because QTP cannot detect the hierarchy of object within Flash Player so it simply identifies it an the ActiveX object, i.e. the ActiveX Flash Player. When you see this happen there should be trace of the error message that has occurred for you to check. Most frequently the error message will be “2 matches for criteria {...}”, this generally means that QTP found 2 or more objects that appear to be the same. By default QTP will only use the type of the object, the automationName and the object's location to uniquely identify it, so if multiple objects exist that are the same type and have the same or no automation name then this error will occur. Remember that QTP does not necessarily see the same hierarchy of objects that actually exist in your view. Components that are under different parents may appear to be under the same parent to QTP if the common parent has its showInAutomationHierarchy set to false. This problem can easily be solved by picking unique automation names and including extra containers in the automation hierarchy to ensure uniqueness.

When built with automation support, mouse clicks only propagate through one level of the view hierarchy. This means that if you have a container on top of another component, say a button, you will not be able to press the button, and hence record clicks on it.  Details of this "bug" can be found here. One way around this is to rearrange your view so the component you wish to interact with is on top of the container, alternatively you can set mouseEnabled to false on the container so the event propagates through.

The performance of recording and replaying QTP scripts should generally be good on a small application but it can become a problem on larger applications. QTP descends the view hierarchy looking for the components to interact with, this can become slow in certain situations. It seems that the search works much better if your tree of components, that QTP sees, is deeper rather than flat. This can easily be achieved by setting showInAutomationHierarchy to true on key containers. This partitions the search space and makes it faster to search, and hence replay scripts. The downside of this is that the scripts recorded will have longer chains of components which couples the scripts even further to the layout of your application. This coupling is a problem when you change the layout of view components in your application because your QTP scripts will need updating to reflect the new layout. Flex 4 claims to improve this performance issue relating to automation.

Sunday, 3 January 2010

Flex/QTP Automation Delegates

In the previous posts I alluded to the fact that you may sometimes have to write custom delegates. Delegates are objects that sit along side every instance of a visual component (when automation is enabled) and interact with the automation software. Delegates exist so that you do not have to place automation related code in you standard components, after all, most people don’t want to run their applications with automation support. Delegates are provided for all the framework classes and will generally work out of the box for any framework class you extend. The need to write custom delegates arrises if you create a custom component that directly extends UIComponent or if you have complex requirements for a component which already has a framework provided delegate.

Delegates register themselves with a given type, for example UIComponentAutomationImpl registers itself as the delegate for UIComponent. When determining which delegate to use for a component the inheritance hierarchy is ascended until a class with a delegate registered is found. If you extend UIComponent then you will, by default, get the delegate for UIComponent. The implementation of UIComponentAutomationImpl provides most of the functionality that you will need for a custom delegate by simply subclassing it.

Automation delegates have two main roles. The first is to record and replay the events generated by user interaction. The second is to provide the automation framework with a collection of automation enabled children. The implementation of UIComponentAutomationImpl does neither of these things by default. In most circumstances, simply recording click events and returning all children is enough to automation enable your component. I have provided a sample implementation below.
[Mixin]
public class ExampleComponentAutomationImpl extends UIComponentAutomationImpl
{
 public function ExampleComponentAutomationImpl( obj : ExampleComponent )
 {
  super( obj );
  recordClick = true;
 }
  
 public static function init( root : DisplayObject ) : void
 {
         Automation.registerDelegateClass( ExampleComponent, ExampleComponentAutomationImpl);
 }
  
 override public function get numAutomationChildren() : int
 {
  return ExampleComponent( uiComponent ).numChildren;
 }
  
 override public function getAutomationChildAt( index : int ) : IAutomationObject
 {
  return ExampleComponent( uiComponent ).getChildAt( index );
 }
}
This delegate enables the recording of clicks by setting a property in the super class. If you wish to listen for other events then you should add listeners in the constructor, you can follow the example of UIComponentAutomationImpl to do this. This implementation also overrides the two functions (get numAutomationChildren and getAutomationChildAt) needed to enable a component’s children to be found by the automation framework. You could put more complex logic in these functions to exclude certain children. The only code here that may strike you as slightly strange is the use of the [Mixin] metadata. This is an almost undocumented feature that ensure that the init function of a class will be called at class loading (generally application startup). We need this “bootstrap” to initially register our delegate before any instances of the related components are created.

Delegates are designed to be non-intrusive objects that can be loaded if necessary when using automation software. This means that your components should never reference a delegate, the result of this is that they will not be compiled into your resulting application. To force this inclusion you need to use the “-includes” compiler argument, which given a list of space separated fully qualified class names ensures that the classes are compiled into the resulting application whether or not they are referenced. The easiest way to maintain this list may be to create a custom flex config file which would take the following format, loading these is described here

<flex-config>
   <includes>
      <symbol>name.space.ExampleComponentAutomationImpl</symbol>
      <symbol>name.space2.ExampleComponentAutomationImpl2</symbol>
   </includes>
</flex-config>

The final step in supporting custom flex components is updating the TEAFlexCustom.xml file which lives in the “QTP_Plugin_Install_Location\Flex 3 Plug-in for Mercury QuickTest Pro” directory. This file is used by QTP to find out the events, properties and function that can be accessed on the components. This file must be maintained to match the components and delegates. A good guide to editing this file can be found here. One point to clarify is the forVerification and forDescription attributes of properties. forDescription specifies if the property can be used to help uniquely identify the component and forVerification specifies if the property can be verified during a test.