Search Wiki:

WF4 Workflow Test Helper (Project Retired)

Utility for helping you to unit test Windows Workflow Foundation (System.Activities from .NET 4)



Use Microsoft.Activities.UnitTesting instead

We are happy to announce that this project has been promoted from a sample to a library on our site.
The namespace has been changed to Microsoft.Activities.UnitTesting and there have been some other changes but you should be able to migrate your tests by simply using the new library.

  • Test Activities - DiagnosticTrace, TestBookmark
  • Test all kinds of workflows using WorkflowInvoker, WorkflowApplication or WorkflowServiceHost
  • Automatically captures tracking information allowing you to use LINQ to search for tracking data
  • Includes memory based persistence store allowing you to test persistence and correlation keys
  • Captures text from WriteLine activities automatically
  • Use XamlInjection to substitute Mock Activities when testing

How To


Test Activities

DiagnosticTrace - allows you to output a System.Diagnostics.Trace message as well as a custom tracking record


TestBookmark<T> - allows you to create a bookmark with a name provided in an expression


Utility Classes

WorkflowInvokerTest - Helps you to write unit tests with simple activities while capturing tracking information and output arguments
public void ShouldAddGoodSumAssertOutArgument()
    var sut = new WorkflowInvokerTest(new GoodSum {x = 1, y = 2});
    sut.AssertOutArgument.AreEqual("sum", 3);

WorkflowApplicationTest - Helps you to write unit tests using WorkflowApplication for workflows that are more complex requiring support for bookmarks. Also captures all event args and tracking information

public void ShouldTestActivityWithBookmarks()
    // Arrange
    var wfAppTest = WorkflowApplicationTest.Create(new ActivityWithBookmarks());
    // Act
    // Assert
                    wfAppTest.TestWorkflowApplication.ResumeBookmark("GetNumber2", 2));
                    wfAppTest.TestWorkflowApplication.ResumeBookmark("GetNumber3", 3));
    wfAppTest.AssertOutArgument.AreEqual("Number", 6);

AssertOutArgument - Allows you to assert that an out argument with the given name exists, is of the same type as the expected value and provides AreEqual, AreNotEqual, IsNull, IsNotNull etc. Exposed through WorkflowTestApplication class as a property
    // Assert
    wfAppTest.AssertOutArgument.AreEqual("Greeting", expectedGreeting);
    wfAppTest.AssertOutArgument.AreNotEqual("WorkflowThread", testThread);
    wfAppTest.AssertOutArgument.AreEqual("WorkflowThread", actionThread);

WorkflowTestResults - Captures all the event arguments provided from WorkflowApplication along with tracking records - access through the WorkflowTestApplication.Results property

AssertTracking - Asserts that tracking records exist after test run

WorkflowServiceTestHost - Hosts a WorkflowService (.xamlx) and captures tracking for testing
public void ShouldHostService()
    var trackingProfile =
        new TrackingProfile
                Queries =
                        new ActivityStateQuery
                                ActivityName = "ReceiveRequest",
                                States = {"Executing"},
                        new ActivityStateQuery
                                ActivityName = "SendResponse",
                                States = {"Executing"},
    using (var host = WorkflowServiceTestHost.Open("TestService.xamlx", _serviceAddress.Uri, trackingProfile))
        var client = ChannelFactory<ITestService>.CreateChannel(_binding, _serviceAddress);
        var response = client.GetData(1);
        Assert.AreEqual("1", response);
        // Find the tracking records for the ReceiveRequest and SendResponse
        // Activity <ReceiveRequest> state is Executing
        AssertTracking.ExistsAt(host.Tracking.Records, 0, "ReceiveRequest", ActivityInstanceState.Executing);
        // Activity <SendResponse> state is Executing
        AssertTracking.ExistsAt(host.Tracking.Records, 1, "SendResponse", ActivityInstanceState.Executing);

MemoryStore - A memory based PersistenceStore allows you to test workflows that become idle, persist and reload. WorkflowServiceTestHost automatically adds this as the persistence store.

/// <summary>
///   Demonstrates how to test a service with correlation
/// </summary>
/// <remarks>
///   Be sure to enable deployment - the xamlx file must be deployed
/// </remarks>
public void ShouldCorrelateServiceCalls()
    using (var testHost = new WorkflowServiceTestHost("ServiceWithCorrelation.xamlx", _serviceAddress.Uri))
        // Add an idle behavior to unload as soon as idle is detected
        testHost.Host.Description.Behaviors.Add(new WorkflowIdleBehavior
                                                    {TimeToUnload = TimeSpan.Zero});
        var client = ChannelFactory<IServiceWithCorrelation>.CreateChannel(_binding, _serviceAddress);
        Trace.WriteLine("Test Client: Sending GetData(1)");
        var response = client.GetData(1);
        Assert.AreEqual("1", response.Text);
        Trace.WriteLine(string.Format("Test Client: Received GetData response {0} with key {1}", response.Text,
        // Wait for unload
        // If you want to see what is in the memory store, dump it
        // MemoryStore.Dump();
        Trace.WriteLine(string.Format("Test Client:  Sending GetMoreData(2, {0})", response.Key));
        var secondResponse = client.GetMoreData(2, response.Key);
        Assert.AreEqual("2", secondResponse.Text);
        Trace.WriteLine(string.Format("Test Client: Received GetMoreData response {0} with key {1}", secondResponse.Text,
        Assert.AreEqual(1, MemoryStore.LoadWorkflowCommandCount);
        Assert.AreEqual(1, MemoryStore.LoadWorkflowByInstanceKeyCommandCount);
        Assert.AreEqual(3, MemoryStore.SaveWorkflowCommandCount);
        Assert.AreEqual(1, MemoryStore.CreateWorkflowOwnerCommandCount);

XamlInjector - Allows you to substitute mock activities when testing Activities or WorkflowServices
public void ShouldReplaceTypesInXaml()
    var xamlInjector = new XamlInjector("TestInject.xaml");
    // The first TestActivity1 will not be replaced - will add 1 to sum
    // Replace the second TestActivity1 with TestActivity2 - will add 2 to sum
    xamlInjector.ReplaceAt(1, typeof (TestActivity1), typeof (TestActivity2));
    // Replace third TestActivity1 with TestActivity3 - will add 3 to sum
    xamlInjector.ReplaceAt(2, typeof (TestActivity1), typeof (TestActivity3));
    // Replace all (2) TestActivity4 with TestActivity5 - will add 10 to sum
    xamlInjector.ReplaceAll(typeof (TestActivity4), typeof (TestActivity5));
    var activity = xamlInjector.GetActivity();
    Debug.WriteLine(string.Format("Invoking Injected XAML activity {0}", activity.GetType()));
    var wiTest = new WorkflowInvokerTest(activity);
    // Act
    // Total should be 1+2+3+10=16
    wiTest.AssertOutArgument.AreEqual("sum", 16);


v 1.5

v 1.4

  • Changes to support XamlInjection
  • Added WorkflowInvokerTest

v 1.3

  • Modified TestBookmark to use a generic argument TestBookmark<T> and changed the namespace to WorkflowTestHelper.Activities. If you used this activity in XAML just check the namespace declaration and add the type argument to your XAML <wa:TestBookmark x:TypeArguments="x:String"
  • Modified WorkflowApplicationTest<T> to create the WorkflowApplication when constructed and accept an input dictionary in the Create call. This allows you to access the WorkflowApplication member sooner and add extensions etc.
  • Added WorkflowApplicationTest.TextLines property - WorkflowApplicationTest will add a StringWriter extension so it will automatically capture all WriteLine activity output.
  • Added WorkflowApplicationTest.Bookmarks property that contains a list of strings with bookmark names.

v 1.2

  • Added support for MemoryStore
Last edited Jul 25 2011 at 3:07 PM  by RonJacobs, version 26
fleed wrote  Nov 1 2010 at 6:43 AM  
It saves lot of time debugging and verifying workflows.
Thank you very much!

Page view tracker