Unit testing Workflow Foundation Bookmarks... easily...

posted on 18 Dec 2013 | Unit Testing | Workflow

I'm not a fan of Workflow Foundation, but you got to do what you got to do. Usually when using WF, unit testing an activity is rather easy. Invoke with some data, assert the out value, possibly watch some methods on some dependencies...

But when it comes to testing Bookmarks, if the bookmark is created, and resuming it, it's not easy...

Well that is unless you're using Microsoft.Activities.UnitTesting

So creating some new projects, a workflow project and a class library for testing...

Next we want to add the MS Libraries:

This will add:

Microsoft.Activities.UnitTesting

and

Microsoft.Activities.Extensions

I've also added xUnit for testing :)

Now we can create a basic workflow activity:

using System.Activities;

public class SampleActivity : NativeActivity<bool>
{
    public InArgument<int> ValueOne { get; set; }
    public InArgument<int> ValueTwo { get; set; }

    protected override bool CanInduceIdle
    {
        get { return true; }
    }

    protected override void Execute(NativeActivityContext context)
    {
        var valueOne = context.GetValue(ValueOne);
        var valueTwo = context.GetValue(ValueTwo);

        if (valueTwo % 2 == 0)
        {
            //We do something and return true...
            context.SetValue(Result, true);

            return;
        }

        // Else condition was not met so we sleep and come back later
        context.CreateBookmark("Bookmark_" + valueOne, ResumeBookmarkCallback);
    }

    private void ResumeBookmarkCallback(NativeActivityContext context, Bookmark bookmark, object value)
    {
        // When we wake up, return false and let it try again
        context.SetValue(Result, false);
    }
}

Note: Post isn't about workflow, it's about unit testing. This is just a random example. :)

So completely random, given valueTwo mod 2 equals 0 then we should set the return value as true, else we create a bookmark... and when the bookmark is woken, it returns false.

The first thing we want to test is the super duper happy path, given valueTwo is 10 then we should get 0 remaining and we can assert that the result is true.

[Fact]
public void Given_10_For_Value_Two_Should_Have_A_Return_Argument_Of_True()
{
    // Arrange
    var wfTester = WorkflowApplicationTest.Create(new SampleActivity
    {
        ValueOne = 123,
        ValueTwo = 10
    });

    // Act
    wfTester.TestActivity();

    // Assert
    wfTester.AssertOutArgument.IsTrue("Result");
}

Here we create an instance of the WorkflowApplicationTest class, passing in an activity with data.

Next we call TestActivity and then we Assert the value.

Sure enough, it passes :)

Now, given the value 9, we should get a bookmark named Bookmark_123

[Fact]
public void Given_9_For_Value_Two_Should_Have_Bookmark_Using_Value_One()
{
    // Arrange
    var wfTester = WorkflowApplicationTest.Create(new SampleActivity
    {
        ValueOne = 123,
        ValueTwo = 9
    });

    // Act
    wfTester.TestActivity();
    wfTester.TestWorkflowApplication.GetBookmarks();

    // Assert
    Assert.Equal("Bookmark_123", wfTester.Bookmarks.First());
}

Like the first test, we start out the same, except after we call TestActivity we actually call GetBookmarks off the TestWorkflowApplication

This is rather important, I couldn't find this in any of the documentation, but without this, the Bookmarks property is always empty...

So by having the GetBookmarks call, ensures the Bookmarks property is populated.

Now, lastly we want to resume the bookmark and assert that the result is returned. We are expecting false so we create a new test, similar to the last, but we resume...

[Fact]
public void When_Resuming_A_Workflow_Should_Get_The_Return_Value_False()
{
    // Arrange
    var wfTester = WorkflowApplicationTest.Create(new SampleActivity
    {
        ValueOne = 123,
        ValueTwo = 9
    });

    // Act
    wfTester.TestActivity();
    wfTester.TestWorkflowApplication.ResumeBookmark("Bookmark_123", 0);

    // Assert
    wfTester.AssertOutArgument.IsFalse("Result");
}

So again, it's similar to the second test, except rather than call GetBookmarks we called ResumeBookmark, passing in the bookmark name, and a value. Although in our case we don't need it, so I passed in 0.

null is not allowed :(

Then we assert that the value is false!

And that's it! A passing unit test! Easy peasy :)

I've put this test into a github repository that can be found here:

https://github.com/phillip-haydon/WorkflowBookmarkUnitTest.git

comments powered by Disqus