incubator-flex-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Heidegger ...@leichtgewicht.at>
Subject [RT] From Singletons to Unit-testable code
Date Tue, 07 Feb 2012 20:11:36 GMT
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.


Mime
View raw message