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();
}
}