Jaa


New Release Microsoft.Activities.UnitTesting 1.71

Just posted a new release of Microsoft.Activities.UnitTesting

This release incorporates the Task Parallel Library to greatly simplify test code.

Episodes

You can now create a task that will run an episode of work in the workflow. An episode is simply a pulse of work that the workflow runs.
For example an episode might look like the following

Thread

Action

host

Run the workflow

host

Wait for idle

Workflow

Activity 1

Workflow

Activity 2 (creates a bookmark)

Workflow

Invoke Idle delegate - host sets event

host

episode complete

Episodes can end in the following ways as defined by the new EpisodeEndedWith enum

Enum

Description

Timeout

The episode did not end within the timeout

Aborted

The episode aborted due to an unhandled exception

Completed

The episode ended when the workflow completed

Idle

The episode ended when the workflow became idle

Should Idle end an episode?

Ending an episode on idle is tricky because there are some idle events that you might not want to end a workflow. For example async activities such as the Delay activity will cause the workflow to idle. If you are testing a workflow and you want test what happens after the delay you don't want the idle to end the episode. In other cases you might want to wait the second or third idle or for an idle where there is at least one bookmark.
The Async Episode methods offer overloads that allow you to control how an episode ends.

Option

Description

Default

An episode ends when completed or aborted

Idle Count

An episode ends when the specified idle count occurs

Func<WorkflowApplicationTest, bool>

You provide a function that will be invoked when idle is detected allowing you to determine if the episode should end. The function receives the active WorkflowApplicationTest object which has captured all the event arguments and tracking data as well as the last known bookmark count to help you make your decision

Async Methods

Method

Description

WorkflowApplicationTest.ResumeBookmarkAsync

returns a Task that will resume a bookmark to run an episode of work.

WorkflowApplicationTest.RunAsync

returns a Task that will run an episode of work.

WorkflowApplicationTest.TestActivityAsync

returns a Task that will run an episode of work.

Examples

Use the default to run until complete or abort

 /// <summary>

/// Verifies that an episode ended with abort

/// </summary>

[TestMethod]

public void EpisodeShouldEndInAbort()

{

    // Arrange

    var host = WorkflowApplicationTest.Create(GetSequenceThatAbortsAfterAsync());



    // Act

    try

    {

        // Run the activity until it aborts, the activity will go idle once 

        // because of the TestAsync activity.

        Assert.AreEqual(EpisodeEndedWith.Aborted, host.TestActivityAsync().Result.EpisodeResult);

    }

    finally

    {

        // Track the tracking records to the test results

        host.Tracking.Trace();

    }

}

Use the idleCount to run until n number of idle events

 /// <summary>

/// Verifies that an episode of work ended with an idle event

/// </summary>

[TestMethod]

public void EpisodeShouldRunToIdleAndThenToCompletedAfterResumeBookmark()

{

    // Arrange

    var host =

        WorkflowApplicationTest.Create(

            new Sequence

                {

                    Activities = 

                    {

                        new WriteLine(), new TestBookmark<int> { BookmarkName = "Bookmark1" } 

                    }

                });



    try

    {

        // Act

        // Run the activity to the first idle

        Assert.AreEqual(EpisodeEndedWith.Idle, host.TestActivityAsync(1).Result.EpisodeResult);



        // Resume the bookmark and run the activity to completion

        Assert.AreEqual(EpisodeEndedWith.Completed, host.ResumeBookmarkAsync("Bookmark1").Result.EpisodeResult);

    }

    finally

    {

        host.Tracking.Trace();

    }

}


Use the Func<WorkflowApplicationTes, bool> method to run a workflow until an idle with at least 1 bookmark

 /// <summary>

/// Verifies that an episode of work idles, then resumes to completion

/// </summary>

[TestMethod]

public void EpisodeShouldRunToIdleAndThenToCompletedAfterResumeBookmark()

{

    // Arrange

    var host =

        WorkflowApplicationTest.Create(

            new Sequence

                {

                    Activities = 

                    {

                        new WriteLine(), new TestBookmark<int> { BookmarkName = "Bookmark1" } 

                    }

                });



    try

    {

        // Act

        // Run the activity to the first idle

        Assert.AreEqual(EpisodeEndedWith.Idle, host.TestActivityAsync(1).Result.EpisodeResult);



        // Resume the bookmark and run the activity to completion

        Assert.AreEqual(EpisodeEndedWith.Completed, host.ResumeBookmarkAsync("Bookmark1").Result.EpisodeResult);

    }

    finally

    {

        host.Tracking.Trace();

    }

}

Comments

  • Anonymous
    January 10, 2011
    With Microsoft.Activities.UnitTesting, is there any way to autogenerate the IServiceWithCorrelation (equivalent) interface for a particular xamlx, or does it always have to be recoded up manually every time the service changes?

  • Anonymous
    January 11, 2011
    IServiceWithCorrelation is just an interface I made up to test a specific workflow service.  I used a technique to create a workflow service that implements a contract (similar to the Contract First extensions we showed at PDC) So yes you must update your interface if the associated workflow breaks the contract in some way.

  • Anonymous
    January 11, 2011
    Thanks Ron. Actually I subsequently realised that I can just add a service reference to my unit test project, and then just use the auto-generated interface within the reference.cs. This is great, as not only does it autogenerate via a single click when the workflow changes, but it avoids me having to write it manually in the first place!