Professional Documents
Culture Documents
testing.
How they improve TDD &
Architecture
Purpose to demonstrate and promote the
utility of IOC Containers for improving
primarily unit testing coverage.
First must show that container
injection has advantages over
manual injection wrt to looser
coupling in classes.
Manual Injection - Is ok. Especially if the dependency (helper)
is created and destroyed with the class using it.
In ClassA In Helper
In ClassA In Helper
}
TDD often requires some form of injection in order to build
effective unit tests. This is due to the fact that in order to run a
test on a piece of code, often the dev will need to pass the code a
dummy or null object or a stub.
This dummy null or stub object
needs to be created somewhere
and then injected.
This means that all those classes need to be created and work
correctly before we can do tdd for our method.
I could instantiate the stub in the testCase, but it may be used again, provided
devs are aware of it and if I put it in a config file it would make other
developers aware of it more easily. Rather than wasting time searching for it.
Without a config file once found this stubdata is often copy pasted into
another test case, potentially duplicating errors and bad coding standards
flagged by FlexCPD.
With a central repository of useful objects they can refer to in writing later
tests.
It's also good OOP to separate object creation from its use.
This is the utility of the container and in doing it
this way we encourage dependency injection rather than procedural
programming where it applies.
Create the stub in the testcase class. More difficult
for another developer to locate objects for reuse.
private function createStubMetricData():void
{
//Metric 1
var metadataItem1:ProductMetaDataVO = new ProductMetaDataVO();
metadataItem1.CompositeScoreWeight = 1;
var metric1:Object = {};
metric1.name = "metric1";
metric1.metadataItem = metadataItem1;
//Metric 2
var metadataItem2:ProductMetaDataVO = new ProductMetaDataVO();
metadataItem2.CompositeScoreWeight = 1;
var metric2:Object = {};
metric2.name = "metric2";
metric2.metadataItem = metadataItem2;
//Metric 3
var metadataItem3:ProductMetaDataVO = new ProductMetaDataVO();
metadataItem3.CompositeScoreWeight = 0;
var metric3:Object = {};
metric3.name = "metric3";
metric3.metadataItem = metadataItem3;
stubMetricData.push(metric1);
stubMetricData.push(metric2);
stubMetricData.push(metric3);
}
With a container this becomes...
Context (Config Class) Test Case Class
public var stubMetricData:Array; //constructor
TestCase ():void
...... {
stubMetricData = createStubMetricData(); addContext()
}
private function createStubMetricData():Array
{ public function setup()
{
...as before.... addContext()
}
return stubMetricDataArray;
......
} [Inject]
public var stubMetricData;
//Now this can be easily found and reused.
private function addContext():void
{
var context : Context = ActionScriptContextBuilder.
build(ExampleASConfig); context.
createDynamicContext().addObject(this);
}
What's the difference between all these
tests!
SEE!
http://www.javaranch.
com/journal/200603/EvilUnitTests
.html#toofunc
Containers for Unit Testing
class A
model
helperModel
Rather than this which often arises from
manual dependency injection.
These 'unit tests' are really functional tests the lines represent the
dependencies.
class A
model
Classes depended on that
should be stubbed.
helperModel
vs
<mx:Script>
[Bindable]
public var model:MyComponentPM;
</mx:Script>
...
</example:MyComponent/>
Better this way with container injection looser coupling no
reference to child componentPM
<example:MyComponent ...
addedToStage="dispatchEvent(new Event('configureIOC', true'))">
<mx:Script>
[Inject]
[Bindable]
public var model:MyComponentPM;
</mx:Script>
<example:MyChildComponent/>
...
</example:MyComponent/>
Why use containers - Agility!
}
*/
A setup method that should be made of a context file(s) and
injected.
override public function setUp():void
{
//This stuff should be in a ContextFile.
var localisedSettings:LocalisedSettings = new LocalisedSettings({});
localisedSettings.addProperties({'dh_Ranger_Thousand_Separator':','});
localisedSettings.addProperties({'dh_Ranger_Decimal_Separator':'.'});
var configurationSettings:Object = {'dh.ranger.flex.defaultcurrencysymbol':'£','dh.ranger.flex.currencysymbolalign':'L'};
level1GroupVO.GroupProducts = createFourGroupedProductsNoneExcluded();
groupVO = level1GroupVO;
presentationModel.groups.addItem(level1GroupVO);
var productCodeReferenced_productDataAttributeVO_ObjectProxies:Array =
[
new ObjectProxy({ "12345": attrs1 }), new ObjectProxy({ "12346": attrs2}), new ObjectProxy({ "12347": attrs3 }), new ObjectProxy({ "12348": attrs4 })
];
var productData:Array = productCodeReferenced_productDataAttributeVO_ObjectProxies;
http://www.javaranch.com/unit-testing/
http://opensource.adobe.
com/wiki/display/cairngorm/BestPracticesAgileUnitTesting
http://www.javaranch.com/unit-testing/too-functional.jsp
http://www.javaranch.com/unit-testing/software-testing-
vocabulary.jsp
Links
http://www.adobe.com/devnet/flex/articles/ioc_frameworks.html
http://martinfowler.com/articles/injection.
html#ConcludingThoughts