On 07/02/2012 09:35, Michael A. Labriola wrote:
Unfortunately, with a few exceptions, unit tests *cannot* be written for the Flex framework. It isn't something that can be started.
Actually those "few exceptions" are quite many to me:
<https://svn.apache.org/repos/asf/incubator/flex/whiteboard/frameworks/projects/framework/src/mx/binding/>mx.binding.*
mx.utils.*
mx.collections.*
mx.events.*
mx.formatters.*
mx.geom.*
mx.graphics.*
mx.logging.*
mx.resources.*
mx.validators.*
mx.messaging.*
...

And yes: some of those classes do have "singletons" which means that the unit tests will be dirty a little. But never-the-less unit tests can be written for what looks like a quite big part of the project.
Unit tests by definition involve the writing of a test for a single object isolated from all other objects, not dependent upon global state, that also means they can't be dependent upon things like the frame rate and enter frame events. Looking at something like UIComponent, it references singletons and static classes (global state). It is coupled tightly with dozens of other objects. It relies upon the LayoutManager, which relies upon the frames, to function.
Any system has at some point a static value. Java has it Thread.currentThread(), PHP has global constants, etc. If we could pull it of to create a unit test that encapsulates a component.

Take this part of the framework:
mx_internal static function get embeddedFontRegistry():IEmbeddedFontRegistry {
    if (!_embeddedFontRegistry && !noEmbeddedFonts) {
       try {
_embeddedFontRegistry = IEmbeddedFontRegistry( Singleton.getInstance("mx.core::IEmbeddedFontRegistry"));
       } catch (e:Error) {
           noEmbeddedFonts = true;
       }
   }
   return _embeddedFontRegistry;
}

If we were to create a unit test environment that compiles against a UIComponent with a different set of code like: mx_internal static function get embeddedFontRegistry():IEmbeddedFontRegistry {
   throw new RequiresFontRegistryError();
}
then if some part of the UIComponent that is being tested that relies on the font-registry would notify the test unit framework: "hey this component needs to be tested with a font registry". The unit-test writer now needs to Create two different subsets of his unit test: One in case the font-registry is given and one in case it isn't. Once he distinguished both tests the unit test framework has to run in both environments:

mx_internal static function get embeddedFontRegistry():IEmbeddedFontRegistry {
   return _embeddedFontRegistry||=new TestFontRegistry;
}
and
mx_internal static function get embeddedFontRegistry():IEmbeddedFontRegistry {
   return null;
}

A definition could look like this:
class UIComponentTest implements IStateTestSuite {
   public function get stateTests(): StateTestMap {
      var map: StateTestMap = new StateTestMap();
map.set(ClassicTestContext, [UIComponentClassicTest]); // Classic test for things without static references (don't need to be tested within a context) map.set(FontTestContext, [UIComponentFontRegistryEnabledTest, UIComponentFontRegistryNullTest]); // FontTestContext will take two tests and run them in a endabled and disabled state.
      return map;
   }
}

I know it sounds like a horrible lot to write and test, but lets face it: It will not be simple to test code that relies on 14000 lines of a monolith that spreads its wings. I think with a little imagination, lots of willpower and a huge amount of coffee it might actually be testable.

yours
Martin.






Reply via email to