Hello List,

when thinking about unit testing of Flex components I got a strong argument against it due to the heavy use of Singletons throughout the project. I think I might have a good refactoring path to ease the transition from the current code to a code that might be easier manageable.

The following process has the advantage that from an early stage it would be possible to write unit tests and at all times it can still be deployed!

1) Create a global context system

  interface IFlexContext {
    function getProperty(name: String):* {}
  }
  public static var FLEX_CONTEXT: IFlexContext = new DefaultFlexContext();

2) copy the code that currently resides in static methods to the DefaultFlexContext();

mx_internal static function get embeddedFontRegistry():IEmbeddedFontRegistry {
     return FLEX_CONTEXT.getProperty("UIComponent.embeddedFontRegistry");
  }
   class DefaultFlexContext {
     function getProperty(name: String): * {
       if( name =="UIComponent.embeddedFontRegistry" ) {
         if (!_embeddedFontRegistry && !noEmbeddedFonts) {
           try {
_embeddedFontRegistry = IEmbeddedFontRegistry( Singleton.getInstance("mx.core::IEmbeddedFontRegistry"));
           } catch (e:Error) {
             noEmbeddedFonts = true;
           }
         }
         return _embeddedFontRegistry;
       }
     }
  }

3) We create unit tests that use these contexts to see with a blind implementation if certain parts of code rely on those static mechanisms. In a way that we can interact with them. From now on all changes will reflect in broken unit tests. Yey! Also no API is broken in the system. This is very important!

4) When we have the unit tests up and running we start to remove the static calls to use the context instead:

   return embeddedFontRegistry;

becomes:

   return FLEX_CONTEXT.getProperty("UIComponent.embeddedFontRegistry");

5) We put the Flex context in a private variable that can be set from outside.

  return FLEX_CONTEXT.getProperty("UIComponent.embeddedFontRegistry");

   becomes:

    private var _context: IFlexContext = FLEX_CONTEXT;
    public function set context(context: IFlexContext) {}

   ....
   return _context.getProperty("UIComponent.embeddedFontRegistry");

6) We adapt the unit tests to actually set this context per instance instead of setting the context globally

7) We change the logic of addChild/removeChild to automatically set the current context

8) We extract the different modules in own variables
    private var _fontContext: IFontContext;

    return _fontContext.getProperty("embeddedFontRegistry");

9) We reintroduce custom methods:

     return _fontContext.embeddedFonts;

I know that this approach is quite a long one but I think it could be done step by step without creating too much friction at each point in time.

What do you think?

yours
Martin.

Reply via email to