Friday 17 June 2011

Making Flex More Testable: Part 1

Testing is a fundamental aspect of any enterprise development; it underpins the assurance we need to provide that our application does what it is supposed to, aids confidence in refactoring and when working in a TDD paradigm, is an integral part of development. This is the first of a multi-part series that aims to address some of the difficulties faced when trying to develop testable code that involves the use of core Flash or Flex libraries.

One software concept that makes proper unit testing difficult is static references, as they introduce dependent coupling that is very difficult to break. This makes testing in isolation very difficult to achieve, and in some cases can make automated testing impossible (due to referencing external resources which may not be available in the test environment). It's one thing to keep this in mind when designing our own implementations, but the Flash Player and Flex Frameworks have their own static methods and variables we need address.

ExternalInterface
Classes like ExternalInterface provide utility functionality through a series of static properties and methods. As this class' prototype is purely static in nature, my preference to break the coupling is to write an interface that has the same footprint as ExternalInterface, minus the static declarations. For example:

package
{
 public interface IExternalInterface
 {
  /**
   * Indicates whether this player is in a container that offers an external interface.
   */
  function get available(  ): Boolean;

  // ...

  /**
   * Registers an ActionScript method as callable from the container. After a successful
   * invocation of addCallBack(), the registered function in Flash Player can be called
   * by JavaScript or ActiveX code in the container.
   * 
   * @param functionName The name by which the container can invoke the function.
   * 
   * @param closure   The function closure to invoke. This could be a free-standing
   *       function, or it could be a method closure referencing a method
   *       of an object instance. By passing a method closure, you can direct
   *       the callback at a method of a particular object instance.
   */
  function addCallback( functionName: String, closure: Function ): void;

  // ...
 }
}


This interface can then be referenced by any classes that depend upon ExternalInterface. In order to complete the implementation, we need to write a basic wrapper class that implements our new IExternalInterface interface, and delegates calls off to ExternalInterface. Whilst this class will contain static references, we are isolating them from the remainder of the application. For example:

package
{
 /**
  * A wrapped implementation of ExternalInterface, for decoupling and dependency injection.
  * 
  * @see flash.external.ExternalInterface
  * @see IExternalInterface
  */
 public class WrappedExternalInterface implements IExternalInterface
 {
  /**
   * @inheritDoc
   */
  public function get available(  ): Boolean
  {
   return ExternalInterface.available;
  }

  // ...
 }
}


Lastly, all that's needed is to wire this up. With RobotLegs/SwiftSuspenders (my current MVCS and dependency injection framework of choice), this would look something like:

injector.mapSingletonOf( IExternalInterface, WrappedExternalInterface );


However, it is worth nothing that even without a Dependency Injection framework in place, there is a lot of benefit to be had by decoupling these sort of static references and manually wiring up the dependent wrapper classes.

Application
At some point, Flex projects will invariably require access to Application.application (Flex 3) or FlexGlobals.topLevelApplication (Flex 4). Removing these static references are not as straightforward as the previous example; we reference it as a dependency and have our dependency injection framework sort out the wiring, for example:

injector.mapSingleton( Application );

// ...

[Inject]
public var application: Application;

However, mocking the behaviour out at test-time might be a bit challenging. Alternatively, we could take a step back and examine the information we're trying to obtain from the Application instance. For example, trying to determine the application URL may be invalid or unavailable in a testing context. Developing a simple service to provide this information abstracts the implementation and makes testing simpler.

This could be facilitated with a simple service definition, as follows:

package
{
 public interface IApplicationURLProvider
 {
  /**
   * The URL that the application was loaded from.
   */
  function get applicationURL(  ): String;
 }
}

Obviously this is a trivial example, but it can be quite a useful abstraction. On a number of projects that I have been involved with recently, the application URL was used as a reference point for making server-side calls. Due to a number of different reasons, the server-side implementation was not available on the (Flex) developers' machines. Whilst it might have been possible to arrange deployment of the Flex application on the server, this can get quite messy with multiple developers wanting to perform their testing.

Alternatively, we were able to provide a mock implementation for our URL provider, e.g.:

package
{
 public class MockApplicationURLProvider
 {
  /**
   * @inheritDoc
   */
  public function get applicationURL(  ): String
  {
   return "http://my.server.location";
  }
 }
}

This concept is also useful when developing Flex-platform-agnostic library code. For example, I've recently developed a RemoteObject pooling system for communicating with Adobe LiveCycle, but it may be used with Flex 3 or Flex 4. The way that we determine the application URL is different for each of these platforms. The core library implementation just needs to depend upon a service declaration similar to the one above. Then it is possible to develop appropriate adapters for each platform, e.g.:

package
{
 public class Flex3ApplicationURLProvider
 {
  /**
   * @inheritDoc
   */
  public function get applicationURL(  ): String
  {
   return Application.application.url;
  }
 }
}

and

package
{
 public class Flex4ApplicationURLProvider
 {
  /**
   * @inheritDoc
   */
  public function get applicationURL(  ): String
  {
   return FlexGlobals.topLevelApplication.url;
  }
 }
}

Saturday 11 June 2011

Common Mistakes: XML Namespaces and E4X

From time to time I stumble upon application code that has an unusual way of handling XML namespaces. The most common case is where a regular expression substitution (or similar) is used to strip out namespace declarations and references from the raw XML prior to being parsed into an XML object. Whilst this may function correctly accordion to the defined application behaviour, there are more elegant ways to handle namespaces in E4X. Consider the following XML snippet:

<root xmlns:space="http://www.something.com">
 <space:tag>
  <node>Hello, world!</node>
 </space:tag>
</root>

Assuming that this XML has been parsed into an XML variable named xml, we could determine the contents of the node node using the following code:

namespace space = "http://www.something.com";

var helloWorld: String = xml.space::tag.node.toString(  );

That is, we are able to declare a namespace identifier by using the namespace keyword, and then reference it in our E4X statements to select the appropriate nodes (using the same notation that we would use to reference custom namespaces in ActionScript 3). Note that the identifier we declare does not have to match the one used in the XML document - only the namespace URI has to match. The example below is equally correct:

namespace different = "http://www.something.com";

var helloWorld: String = xml.different::tag.node.toString(  );

Using this technique avoids the need to manipulate XML content before it is parsed; it is simpler and avoids the chance of incorrectly preprocessing the data.

Introduction

I've created this blog as a means of documenting my experiences and thoughts on developing enterprise applications that involve the Adobe Flex platform. Much of this will be derived from my professional career, but some may come from my personal interest in the technology, and software engineering in general. It will be a focus on design patterns, methodology, testing and real-world problem solving.