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.