By Sandra Palmer,2014-08-28 02:49
9 views 0

错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 1 of 33

    Design Doc: FAL Design Time TestObjects

    Doc Name TestObjectsDesignDoc.doc

    Doc Status DRAFT

    Doc Milestone WinOE M2


    This document describes the design for WinOE Test Objects at the Functional Action Layer in

    the Design Time. The main focus is describing a model which allows maximum code reuse

    while still maintaining both the product and test hierarchies for switchable test cases between

    VS and ADOM.


    1. Introduction .............................................................................................................................. 1

    2. Functional Design ....................................................................................................................... 1

    3. Design Class Descriptions ............................................................................................................ 8

    4. Impl Interface Descriptions ....................................................................................................... 22

    5. Coding Best Practices ............................................................................................................... 30

    6. Usage Best Practices ................................................................................................................. 33

1. Introduction

    Most positive test cases should be able to run without regard for the method of schedule

    design. Currently, there are two ways to create schedules; they can be authored through the

    ADOM or constructed in the visual designer through VS (Whidbey). It is important to

    determine a test object model structure which facilitates this goal.

    1.1. Requirements

    The main requirements for the Design Time FAL Test Objects are:

    1) Maximize code reuse between VS and ADOM solutions.

    2) Maximize code reuse between activity wrapper classes.

    3) Maintain product hierarchy for ease of schedule building.

    4) Objects exposed to test cases should be backend agnostic.

    2. Functional Design

    A well-known design pattern which addresses these issues and solves this problem is the

    Bridge (Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley,

    1995). The Bridge works by separating the abstraction and the implementation. In our case,

    the abstraction is the set of classes which we want test cases to interact with (DesignCode, Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 2 of 33

    DesignWhile, DesignRule) and the implementation is calls into either the corresponding ADOM or VS object.

    2.1. Abstraction Hierarchy

    The Abstraction tree mirrors the product tree and each class provides the methods described below. The classes in the abstraction hierarchy are concrete and have implementations. From here on, these abstraction classes will be referred to as Design classes (DesignActivity, DesignCode, DesignWhile, etc.).

    The abstraction classes contain all of the common code which spans the VS/ADOM gap. This includes, but is not in any way limited to, all code pertaining to code beside generation, all code pertaining to runtime validation, and all code which wraps other internal method calls. All other design method specific code will be delegated to the correct Implementation class.

    2.2. Implementation Hierarchy

    The first part of the Implementation tree is a set of interfaces. For each Design class which introduces new product functionality there will be an associated Implementation interface to bridge the abstraction to the product. From now on, these will be referred to as Impl interfaces (IActivityImpl, IWhileImpl, IReceiveImpl, etc.).

    Additionally, there are implementations for these interfaces which have a one to one correspondence with the Design classes. For each style of design, such as VS or ADOM, there will be an entire matching hierarchy of implementations. These classes will be referred to as Impl classes from now on with two subsets, the Adom Impl classes (AdomActivityImpl, AdomWhileImpl, etc.) and the VS Impl classes (VSActivityImpl, VSWhileImpl, etc.). As an example, DesignWhile adds the EnableRule property to a DesignComposite. Therefore, an IWhileImpl interface containing an EnableRule property will be created. Additionally, a VSWhileImpl subclass of VSCompositeImpl and an AdomWhileImpl subclass of

    AdomCompositeImpl will be created. DesignWhile will take care of any common code for the EnableRule and then will delegate the call back to its IWhileImpl object.

    The Impl classes contain only specific code. Any code which could be shared across VS and ADOM belongs in the corresponding Design class.

    2.3. Small Proof of Concept

    The following is a small proof of concept containing very partial Activity and Delay classes. However, this sample does show most of what will be discussed in the rest of this document. The comments included describe most of what is happening.

    Consider the following code:

    // These are the Design classes.

    namespace Abstraction


     using Implementation;

     // Design class for Activity

     public abstract class DesignActivity


     private IActivityImpl actImpl;

     public DesignActivity()


     actImpl = null;


     // This constructor is used by subclasses to

     // set all of the base references to the

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 3 of 33

     // Impl interface.

     public DesignActivity(IActivityImpl impl)


     actImpl = impl;


     // An accessor used to get the

     // Activity Implementation object

     protected IActivityImpl ActivityImpl




     return actImpl;



     // This method delegates all of its code

     // to the Impl class because there is nothing

     // common between VS and ADOM.

     public string ID




     return actImpl.ID;




     actImpl.ID = value;



     // Abstract methods for other activities.

     public abstract string GenerateCode();

     public abstract string GenerateTrace();


     // Delay Design class.

     public class DesignDelay: DesignActivity


     private IDelayImpl delayImpl;

     protected string verifyString;

     // This constructor calls the base (DesignActivity)

     // constructor first. Note that it passes the

     // new delay impl as a parameter. This is because the

     // we need to set all of the base class

     // Impl interface references.

     public DesignDelay(ImplFactory factory) :



     delayImpl = (IDelayImpl)this.ActivityImpl;

     verifyString = delayImpl.TimeoutProvider;


     // This is the new functionality of delay.

     // Note that the value verification is common

     // but the real meat of the method is delegated

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 4 of 33

     // to the delayImpl.

     public string TimeoutProvider




     if (verifyString != delayImpl.TimeoutProvider)


     throw new Exception("Error");




     return verifyString;





     delayImpl.TimeoutProvider = value;

     verifyString = value;



     // Provides a generate code implementation.

     // Once again, this code is common.

     public override string GenerateCode()


     return "I generated code beside";


     // Provides a generate trace implementation.

     // Once again, this code is common.

     public override string GenerateTrace()


     return "I generated my trace";




    namespace Implementation


     using IL = IntegrationLayer;

     using Abstraction;

     // Activity interface. New functionality

     // is ID.

     public interface IActivityImpl


     string ID { get; set;}


     // Implementation of activity interface.

     // There will be two of these (VS and Adom)

     // in our case.

     public class MyActivityImpl: IActivityImpl


     private IL.Activity ilAct;

     public MyActivityImpl()


    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 5 of 33

     ilAct = null;


     // Used by subclasses to set the base

     // class IL reference.

     public MyActivityImpl(IL.Activity act)


     ilAct = act;


     // Used by subclasses to access the

     // base class IL reference.

     public IL.Activity ILActivity




     return ilAct;



     // This is the ACTUAL functionality for

     // Activity.

     public string ID







     { = value;




     // Delay impl interface.

     public interface IDelayImpl


     string TimeoutProvider { get; set;}


     // Delay impl class.

     public class MyDelayImpl: MyActivityImpl, IDelayImpl


     private IL.Delay ilDelay;

     // Constructor creates a new IL delay which

     // it passes to the base constructor.

     // Then, it sets its own IL reference.

     public MyDelayImpl() : base(new IL.Delay())


     ilDelay = (IL.Delay)this.ILActivity;


     // Once again, this is the actual

     // product interacting behavoir for

     // Delay.

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 6 of 33

     public string TimeoutProvider




     return ilDelay.timeout;




     ilDelay.timeout = value;




     // This abstract factory is used by

     // the Test Case to generate the correct

     // type of Impl objects. Test case

     // calls CreateFactory() and passes return

     // value to the constructors of the Design

     // classes.

     public abstract class ImplFactory


     public static ImplFactory CreateFactory()


     return new MyImplFactory();


     public abstract IActivityImpl GetActivityImpl();

     public abstract IDelayImpl GetDelayImpl();


     // Concrete implementation of abstract factory.

     // This one is for My*Impl classes, but we will

     // have a VSImplFactory and an AdomImplFactory.

     public class MyImplFactory: ImplFactory


     public override IActivityImpl GetActivityImpl()


     return MyActivityImpl();


     public override IDelayImpl GetDelayImpl()


     return MyDelayImpl();




// The integration layer.

    namespace IntegrationLayer


     // The activity object - wraps

     // the product activity.

     public class Activity


     public string id;


     // The delay object - wraps the

     // product delay

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 7 of 33

     public class Delay: Activity


     public string timeout;



    2.4. Benefits

    There are a few main benefits to this approach:

    2.4.1. Clear separation of code for each activity.

    This technique makes it very clear what code belongs to an activity: the common code (Design class) and the code specific to each design style (Impl classes).

    2.4.2. Maximum code reuse.

    The product hierarchy allows for a lot of code reuse. There is housekeeping which the test infrastructure must do for activities such as Scope and Schedule. Additionally, there is code reuse in the “test” hierarchy. Code generation and expected trace validation generation are designed to work regardless of design style. The Bridge pattern allows us to make use of both avenues of reuse. The Design classes provide code reuse for common functionality while the Impl classes allow code reuse of product calls without locking in any specific design style. 2.4.3. Backend agnostic.

    From the test case point of view there are only Design classes and an abstract ImplFactory with a CreateFactory method. There is nothing which locks a test case into one design style or another.

    2.5. Design Decisions

    2.5.1. Design Class Constructors

    The question was raised whether the Design classes should be instantiated in test cases by allowing the tester to directly call the constructor (make it public) or by forcing the tester to create activities through a factory.

    Since this design pattern allows for all common code to be held in the Design classes there will never be a need to “switch” the implementation with which the test cases deal with. Since this is the main reason for using factories, public constructors were chosen. 2.5.2. ImplFactory Design Class Constructor Parameter

    The ImplFactory should only be created once per test case but needs to be used by every Design class constructor in order to initialize its Impl interface member variables. A singleton (static) instance of the factory was avoided since there would be one per process, not test case. Additionally, creating the factory in each constructor would not work as this would result in multiple factories.

    For those reasons, it was decided to pass the ImplFactory as a parameter to the Design classes. While each test case will need to create the factory explicitly, this does allow for some level of control from the tester’s point of view. By choosing the factory to create, instead of allowing context to do it, the tester can choose how all, or even just a portion, of the test case is run.

    2.5.3. FAL Impl Classes Are Not Integration Layer Classes

    For the ADOM, the FAL Impl classes do not really add anything except a layer of abstraction from the Integration Layer classes. While this makes a decent case for folding the two into

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 8 of 33

    one set, instead we are keeping the two distinct pieces. The benefits are that the ADOM and VS trees will look the same, there is sufficient breathing room if anything changes, and there are a few cases where it is unnecessary, but would be nice, to allow the FAL Impl classes to do a little more than just call the IL classes. On the downside, there is one extra method call for most product related design activities. For the added flexibility this is a performance hit we are willing to take.

    2.5.4. Creating Configured Activities

    Instead of overloading constructors to create “one shot” configured activities, we are implementing static “Create” methods on the activities themselves. For example, DesignWhile will contain a constructor which takes an ImplFactory and returns an object configured with the product defaults. Additionally, a method like CreateFullyConfiguredWhile with an ImplFactory parameter will return a DesignWhile with all necessary properties set to some test chosen defaults. Finally, another method such as CreateConfiguredWhile will take a string ID and a DesignRule as a parameter and use those to set the properties of the DesignWhile it returns.

    This approach was used because it forces good coding habits and clearly separates what objects represent the product and which are modified before being handed to the test case. Additionally, if for any reason we need to change parts of DesignWhile, we will most likely not rdhave to change the “Create” methods since they use the class from a 3 party point of view

    and are forced to only access properties through public members. All in all it reduces possible coding errors that might occur during constructor overloading.

    2.5.5. Create Schedules On Their Own

    ScheduleProject will not be the only way to create a schedule. We will support both creating a DesignSchedule through its constructor and creating one through an already created project. The main reason is to allow test cases to ignore the project aspect if they do not directly require it.

    In order to support both, DesignSchedule will have a Project property which points to the project that it belongs to. When a DesignSchedule instance is created, it will also create a ScheduleProject and add itself. In the same way, if the tester asks the ScheduleProject to add another schedule, it will construct the schedule and set itself as the owning project. This will take care of a lot of housekeeping in common code and should work well across VS (which requires a project) and ADOM (which does not require a project).

    3. Design Class Descriptions

    A description of all the methods found on the design classes. Note that the “Create” methods

    have not yet been added to these listings. These methods are used to create a configured version of the activity and are going to be decided upon shortly.

    3.1. Interface ICodeFileFinder

    This interface is used to denote a class which can figure out which code file and which type it needs to add generated code to.

    Gets the code file associated with this class. CodeFileBuilder CodeFile {get;}

    Gets a reference to the type code should be TypeReference TypeToAddTo {get;}

    added to.

    Gets the fully qualified name of this object in string FullName {get;}

    terms of the scope it belongs to.

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 9 of 33 3.2. Interface IImplFactoryUser

    Get the ImplFactory used by this object. ImplFactory ImplFactory {get;}

3.3. Interface ICodeAndValidationGenerator

    This interface is used to specify classes which generate code, expected traces, and code

    beside validation.

    Generates the associated code. void GenerateCode(CodeFileBuilder codeFile, TypeReference typeToAddTo, bool finalPass)

    Adds all necessary expected trace to void GetExpectedTrace(CompositeTraceStep

    parentStep, string fullNamePrefix, Oracle parentStep. oracle)

    Allows VS to verify the code beside files. void VerifyCodeBeside(string className, CodeBesideVerifier cbv) No op in Adom Impl classes.

3.4. Abstract Class DesignActivity : ICodeFileFinder, ICodeAndValidationGenerator,


    DesignActivity represents the product abstract base activity.

    3.4.1. Product Related Methods/Properties

    Gets or sets the product activity ID. public virtual string ID {get; set;}

    Gets or sets the activity description. public virtual string Description {get; set;}

    3.4.2. Test Related Methods/Properties

    Gets the activity’s fully qualified name. public string FullName {get;}

    Gets or sets the activity’s parent. public DesignCompositeActivity Parent {get; set;}

    Gets the activity specific trace steps such public abstract void

    GetActivitySpecificTrace(CompositeTraceStep as code beside calls or child activity parentStep, string fullNamePrefix, Oracle enablement. The DesignActivity oracle) implementation of GetExpectedTrace()

    takes care of all common activity steps

    (enable, execute, completed, close).

    Gets a reference to the factory used to public ImplFactory ImplFactory {get;}

    create this activity’s implementation.

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

    错误?使用“开始”选项卡将 Title 应用于要在此处显示的文字。 Page 10 of 33

    3.5. Abstract Class DesignComposite : DesignActivity

    3.5.1. Product Related Methods/Properties

    Add an activity to this composite activity. public void AddActivity(DesignActivity act)

    Insert an activity into this composite activity public void InsertActivity(DesignActivity act, int index)

    Remove an activity from this composite public void RemoveActivity(DesignActivity activity. actToRemove)

    Remove an activity at a specific index from public void RemoveActivityAt(int index) this composite activity. 3.5.2. Test Related Methods/Properties

    Get the children of this composite as public DesignActivity[] Children {get;} DesignActivity objects.

    Add a code activity. public DesignCode AddCode()

    Add a conditional activity. public DesignConditional AddConditional()

    Add a conditioned activity. public DesignConditioned AddConditioned()

    Add a constrained activity. public DesignConstrained


    Add a CAG. public DesignConstrainedActivityGroup AddCAG()

    Add a delay activity. public DesignDelay AddDelay()

    Add an event driven activity. public DesignEventDriven AddEventDriven()

    Add an event handler activity. public DesignEventHandler


    Add an event handlers activity. public DesignEventHandlers


    Add an exception handler activity. public DesignExceptionHandler AddExceptionHandler()

    Add an exception handlers activity. public DesignExceptionHandlers

    Microsoft Confidential. Copyright ? 2003 Microsoft Corporation.

Report this document

For any questions or suggestions please email