IOC Containers and Unit Testing

Embed Size (px)

Citation preview

  • 8/14/2019 IOC Containers and Unit Testing.

    1/33

    IOC Containers and Unittesting.

    How they improve TDD &

    Architecture

  • 8/14/2019 IOC Containers and Unit Testing.

    2/33

    Purpose to demonstrate and promote theutility of IOC Containers for improvingprimarily unit testing coverage.

  • 8/14/2019 IOC Containers and Unit Testing.

    3/33

    First must show that containerinjection has advantages over

    manual injection wrt to loosercoupling in classes.

  • 8/14/2019 IOC Containers and Unit Testing.

    4/33

    Manual Injection - Is ok. Especially if the dependency (helper)is created and destroyed with the class using it.

    In ClassA

    public var model:Model;.....

    public var helper:Helper;private var helperModel:HelperModel = model.helperModel ;.....helper = new Helper();helper.helperModel =

    helperModel;

    In Helper

    public var helperModel:HelperModel

    //Constructor

    public function Helper(){.....}

    We are defining helperModel and then using

    this definition to set helperModel on thehelper.

  • 8/14/2019 IOC Containers and Unit Testing.

    5/33

    But it does couple Model andHelperModel In Class A.

    With a container we could have the two classes uncoupled(Sothat ClassA has no reference to her HelperModel) and isolated- especially helpful for unit testing. And preventing even tightercoupling!

  • 8/14/2019 IOC Containers and Unit Testing.

    6/33

    Container Injection - no coupling.

    In ClassA

    public var model:Model;

    .....

    public var helper:Helper;......helper = new Helper();

    In Helper

    [Inject]public var helperModel:

    HelperModel

    //Constructor

    public function Helper(){}

  • 8/14/2019 IOC Containers and Unit Testing.

    7/33

    TDD often requires some form of injection in order to buildeffective unit tests. This is due to the fact that in order to run atest on a piece of code, often the dev will need to pass the code adummy or null object or a stub.

  • 8/14/2019 IOC Containers and Unit Testing.

    8/33

    This dummy null or stub objectneeds to be created somewhere and then injected.

    We have various options all ofwhich are valid:

    1. Use a StubDelegate with the

    same interface as theDelegate.

    2. Create the stub in thetestcase class.

    3. Have Stubs for a class orsuite in a Config class anduse a container.

  • 8/14/2019 IOC Containers and Unit Testing.

    9/33

    Use a StubDelegate with the sameinterface as the Delegate.If using Cairngorm this usually means that the stub is passedacross several classes (by injection) before it's injected into theclass with the method under test.

    This means that all those classes need to be created and workcorrectly before we can do tdd for our method.

    This also encourages thetraversal injection approach.

  • 8/14/2019 IOC Containers and Unit Testing.

    10/33

    Create the stub in the testcase class.

    Better for unit tests as you avoid passing stub data across (not better for

    functional tests).

    I could instantiate the stub in the testCase, but it may be used again, provideddevs are aware of it and if I put it in a config file it would make otherdevelopers 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 standardsflagged by FlexCPD.With a central repository of useful objects they can refer to in writing latertests.

    It's also good OOP to separate object creation from its use.This is the utility of the container and in doing itthis way we encourage dependency injection rather than proceduralprogramming where it applies.

  • 8/14/2019 IOC Containers and Unit Testing.

    11/33

  • 8/14/2019 IOC Containers and Unit Testing.

    12/33

    With a container this becomes...Context (Config Class) Test Case Class

    public var stubMetricData:Array;......stubMetricData = createStubMetricData();private function createStubMetricData():Array{

    ...as before....

    return stubMetricDataArray;

    }

    //Now this can be easily found and reused.

    //constructorTestCase ():void{addContext()

    }public function setup(){

    addContext()}

    ......[Inject]public var stubMetricData;

    private function addContext():void

    {var context : Context = ActionScriptContextBuilder.

    build(ExampleASConfig); context.createDynamicContext().addObject(this);}

  • 8/14/2019 IOC Containers and Unit Testing.

    13/33

    What's the difference between all thesetests!

    SEE!http://www.javaranch.com/journal/200603/EvilUnitTests.html#toofunc

  • 8/14/2019 IOC Containers and Unit Testing.

    14/33

    Containers for Unit Testing

    A Container makes it easier to isolate each class by injectingstubs directly into the class.

    Classes with method to test.

    class A

    model

    helperModel

  • 8/14/2019 IOC Containers and Unit Testing.

    15/33

    Rather than this which often arises frommanual dependency injection.

    hese 'unit tests' are really functional tests the lines represent theependencies.

    Classes with method to test.

    Classes depended on thatshould be stubbed.

    The lines representdependencies like model.helperModel

    class A

    model

    helperModel

  • 8/14/2019 IOC Containers and Unit Testing.

    16/33

  • 8/14/2019 IOC Containers and Unit Testing.

    17/33

    Nothing wrong with a few of themdone by developers.

    ... This way these are actuallyfunctional tests.

    Classes with method to test.

    Classes depended on thatshould be stubbed.

  • 8/14/2019 IOC Containers and Unit Testing.

    18/33

    Thirdly class architecture.

    vs

    We do it this way. Better this way

  • 8/14/2019 IOC Containers and Unit Testing.

    19/33

    With container injection this isstraightforward.

    With the componentizedapproach to the PresentationModel pattern, there is a single

    hierarchy of view components butno hierarchy of presentationmodels. Each view componenthas a corresponding presentation

    model, but these models areindependent of one another.They do need coordination viaa domain model. See links.

  • 8/14/2019 IOC Containers and Unit Testing.

    20/33

  • 8/14/2019 IOC Containers and Unit Testing.

    21/33

    [Bindable]public var model:MyComponentPM;

    ...

    We do it this way, manualinjection (and coupled).

  • 8/14/2019 IOC Containers and Unit Testing.

    22/33

    [Inject][Bindable]public var model:MyComponentPM;

    ...

    Better this way with container injection looser coupling noreference to child componentPM

  • 8/14/2019 IOC Containers and Unit Testing.

    23/33

    Why use containers - Agility!

    A Container allows us to be more agile.Starting TD development before a contract is defined andstubDelegate is complete.

    By creating smaller stubs that involve only units under test.Our code may need refactoring to ensure this.

  • 8/14/2019 IOC Containers and Unit Testing.

    24/33

    Container - decoupling

    The container promotes decoupling which produces betterstructured code.

    Links see other document.

  • 8/14/2019 IOC Containers and Unit Testing.

    25/33

  • 8/14/2019 IOC Containers and Unit Testing.

    26/33

    Containers - Isolation

    This leads to a focus on true unit testing and less functionaltesting that passes a stub delegate across the Cairngormsequence if there's a problem with the sequence we have aproblem with our method under test, by passing the

    dependency manually.

  • 8/14/2019 IOC Containers and Unit Testing.

    27/33

    Containers - Clarity

    Config becomes a central repository of stubs for a particulartest case that other developers can easily be made aware ofand peruse rather than looking through test methods which iswhere they are currently.

  • 8/14/2019 IOC Containers and Unit Testing.

    28/33

    Better Isolation means better methods!

    public function testUpdateModel():void{

    var childVO:ChildVO = childPM.vo as ChildVO;

    childPM.updateModel('@');

    assertEquals('This is the

    childVO@', childVO.title);}

    //really a functional test./* public function testUpdateParentModel():void{

    var parentVO:ParentVO = parentPM.vo as ParentVO;

    childPM.updateParentModel('@')assertEquals('This is a parentVO it

    has the child VO@',parentVO.id);}*/

    public function updateModel(value:*='*'):void{

    if(value!='*')value='@';childVO.update(value);

    //Don't do this its then doing two things atonce implicitly;

    //if(parentPM)//parentPM.updateModel('*');

    //Instead do this you can test this!!!updateParentModel(value);

    }

    public function updateParentModel(value:*):void{

    if(parentPM)

    parentPM.updateModel(value);}

    ChildPMTest ChildPM

    A setup method that should be made of a context file(s) and

  • 8/14/2019 IOC Containers and Unit Testing.

    29/33

    A setup method that should be made of a context file(s) andinjected.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'};

    presentationModel = new ProductGroupsModulePM(1, configurationSettings, localisedSettings);presentationModel.dendrogramData = new DendrogramData([],{},[]);

    //CREATES SEG DATA ON MODEL.createSegmentationData();

    var level1GroupVO:GroupVO = new GroupVO();level1GroupVO.GroupId = 10;

    level1GroupVO.GroupProducts = createFourGroupedProductsNoneExcluded();

    groupVO = level1GroupVO;presentationModel.groups.addItem(level1GroupVO);

    var productDataAttributeVO1:ProductDataAttributeVO = new ProductDataAttributeVO();

    productDataAttributeVO1.AttributeValue = "1000";productDataAttributeVO1.ColumnName = "test";productDataAttributeVO1.ProductCode = "12345";

    var productDataAttributeVO2:ProductDataAttributeVO = new ProductDataAttributeVO();productDataAttributeVO2.AttributeValue = "2000";productDataAttributeVO2.ColumnName = "test";productDataAttributeVO2.ProductCode = "12346";

    var productDataAttributeVO3:ProductDataAttributeVO = new ProductDataAttributeVO();productDataAttributeVO3.AttributeValue = "1000";productDataAttributeVO3.ColumnName = "test";productDataAttributeVO3.ProductCode = "12347";

    var productDataAttributeVO4:ProductDataAttributeVO = new ProductDataAttributeVO();productDataAttributeVO4.AttributeValue = "1000";productDataAttributeVO4.ColumnName = "test";productDataAttributeVO4.ProductCode = "12348";

    var attrs1:Object = { "test": productDataAttributeVO1};var attrs2:Object = { "test": productDataAttributeVO2};var attrs3:Object = { "test": productDataAttributeVO3};var attrs4:Object = { "test": productDataAttributeVO4};

    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;

    var productMetaDataVO:ProductMetaDataVO = new ProductMetaDataVO();productMetaDataVO.ColumnName = "test";productMetaDataVO.IsVisible = true;productMetaDataVO.ResourceKey = "test";productMetaDataVO.FormatType = FormatTypeVO.NUMBER;productMetaDataVO.FormatPrecision = 2;

    productMetaDataVO.FormatMagnitude = null;productMetaDataVO.VisibleToProductMetrics = true;productMetaDataVO.VisibleToGroupMetrics = true;productMetaDataVO.VisibleToGroupSummary = true;productMetaDataVO.VisibleToProductSubstitutes = true;

  • 8/14/2019 IOC Containers and Unit Testing.

    30/33

    Having a setup with reusable stubs.

    override public function setUp() : void{

    var context : Context= ActionScriptConte

    xtBuilder.build(ExampleASConfig);context.createDynamicContext().addObject(this);

    }

  • 8/14/2019 IOC Containers and Unit Testing.

    31/33

    The Container - Formalises DI

    One can look at a class and distinguish more easily betweendepended on and composite objects - ones that live and diewith the class as opposed to those that live on (aggregate). The[Inject] metadata tag makes highlight the classes

    dependencies.

  • 8/14/2019 IOC Containers and Unit Testing.

    32/33

    Links http://www.spicefactory.org/parsley/

    http://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjects

    http://www.javaranch.com/unit-testing/http://opensource.adobe.com/wiki/display/cairngorm/BestPracticesAgileUnitTestinghttp://www.javaranch.com/unit-testing/too-functional.jsp

    http://www.javaranch.com/unit-testing/software-testing-vocabulary.jsp

    http://www.javaranch.com/unit-testing/software-testing-vocabulary.jsphttp://www.javaranch.com/unit-testing/too-functional.jsphttp://opensource.adobe.com/wiki/display/cairngorm/BestPracticesAgileUnitTestinghttp://www.javaranch.com/unit-testing/http://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://www.spicefactory.org/parsley/http://www.javaranch.com/unit-testing/software-testing-vocabulary.jsphttp://www.javaranch.com/unit-testing/software-testing-vocabulary.jsphttp://www.javaranch.com/unit-testing/too-functional.jsphttp://opensource.adobe.com/wiki/display/cairngorm/BestPracticesAgileUnitTestinghttp://opensource.adobe.com/wiki/display/cairngorm/BestPracticesAgileUnitTestinghttp://www.javaranch.com/unit-testing/http://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://opensource.adobe.com/wiki/display/cairngorm/OptionsConstructRetrieveIsolateObjectshttp://www.spicefactory.org/parsley/http://www.spicefactory.org/parsley/
  • 8/14/2019 IOC Containers and Unit Testing.

    33/33

    Links

    The container also facilitates a more decoupledcomponentized structure for presentation models see:http://blogs.adobe.

    com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://www.adobe.com/devnet/flex/articles/ioc_frameworks.html

    http://martinfowler.com/articles/injection.html#ConcludingThoughts

    http://www.adobe.com/devnet/flex/articles/ioc_frameworks.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://martinfowler.com/articles/injection.html#ConcludingThoughtshttp://martinfowler.com/articles/injection.html#ConcludingThoughtshttp://www.adobe.com/devnet/flex/articles/ioc_frameworks.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.htmlhttp://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.html