Once you create your Logical Functional Model the other pieces can follow in any order immediately as chunks of your feature and LFM are defined. I'll follow the most typical pattern here, which brings us to Execution Behaviors.
When you first define your LFM you focus on what the user is doing not how they are doing it. The next step - defining Execution Behaviors - starts to drill down into the how. For each user action you defined in your LFM, determine every possible way the user can invoke that action. For example, every action in Surveyor can be invoked by both the mouse and the keyboard; to indicate they are done with the survey (to nest examples), the user can:
These two possibilities are pretty much it in Surveyor, but the more complicated your application the more execution variants you are likely to have. (To wit: how many different ways can you create a new document in your word processor?)
After you have identified the various Execution Behaviors for an action you organize them in two ways:
Each of these groups translates directly to a Composite Execution Behavior / child Execution Behavior relationship:
Now you're ready to turn your LFM stubs into Composite Execution Behaviors and stub out the corresponding child Execution Behaviors. Surveyor's Logical.Navigation.IndicateAmDone method
public static void IndicateAmDone() { }
becomes
[CompositeExecutionBehavior("IndicateAmDoneUsingMouse", "IndicateAmDoneUsingKeyboard")]public static void IndicateAmDone() { Delegate chosenChild = ExecutionBehaviorManager.ChooseAny(Logical.Navigation.IndicateAmDone); chosenChild();}
public static void IndicateAmDoneUsingMouse() { }public static void IndicateAmDoneUsingKeyboard() { }
Execution Behaviors for creating a new document might code up thusly:[CompositeExecutionBehavior("CreateNewDocumentUsingMenu", "CreateNewDocumentUsingToolbar", "CreateNewDocumentUsingObjectModel")]public static void CreateNewDocument(){ Delegate chosenChild = ExecutionBehaviorManager.ChooseAny(Logical.Documents.CreateNewDocument); chosenChild();}
[CompositeExecutionBehavior("CreateNewDocumentUsingMenuUsingKeyboard", "CreateNewDocumentUsingMenuUsingMouse")]public static void CreateNewDocumentUsingMenu(){ Delegate chosenChild = ExecutionBehaviorManager.ChooseAny(Logical.Documents.CreateNewDocumentUsingMenu); chosenChild();}public static void CreateNewDocumentUsingMenuUsingKeyboard() { }public static void CreateNewDocumentUsingMenuUsingMouse() { }
[CompositeExecutionBehavior("CreateNewDocumentUsingToolbarUsingMouse")]public static void CreateNewDocumentUsingToolbar(){ Delegate chosenChild = ExecutionBehaviorManager.ChooseAny(Logical.Documents.CreateNewDocumentUsingToolbar); chosenChild();}public static void CreateNewDocumentUsingToolbarUsingMouse() { }
public static void CreateNewDocumentUsingObjectModel() { }
Test cases now have a variety of options when they need to create a new document:
This is why I made the "using toolbar" variant a Composite even though it only has a single child - doing so allows test cases to state whether they care how the toolbar button is invoked.
With Execution Behaviors integrated into your LFM you get automatic variation over the full set of execution methods, which lets you write fewer test cases (since you no longer need an explicit test case for each different implementation). Individual test cases however have the flexibility to use a specific implementation, so regression tests and such can still be written against the LFM. This is one case where you really can have it both ways!
*** Want a fun job on a great team? I need a tester! Interested? Let's talk: michhu at microsoft dot com. Great coding skills required.