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.