Testing SharePoint Workflows using TypeMock Isolator

Updated 12 June 2009 - I have been having problems using this technique of Typemock with Sharepoint Workflows, the workflows keep unexpectedly idling as opposed to activating. If you suffer similar problem please check for later posts as to any solutions I find. 

Updated 6 April 2009 – Also see Testing SharePoint Workflows using TypeMock Isolator (Part 2)

I have for a while been trying to test SharePoint workflows using TypeMock Isolator to mock out the SharePoint fixtures, I want to remove the dependency of having SharePoint on any test boxes where possible. I have at last got this working after getting a new version of TypeMock Isolator 5.3.0 + a fix from the very helpful team at TypeMock

My idea was to be able to build a workflow that could changed list item properties for a document e.g. the workflow could set a field called approved to true if certain criteria were met. Now as a MOSS2007 workflow is based on .NET WF I knew I could try to build upon the work I document in my previous post on TDD for WF.

My test system was as follows:

  1. I created a new SharePoint workflow, all it contained was a decision box that went down the true path if the document associated with the workflow has a title starting with the letter A
  2. In a coded action for the true path, I then set an approved property to true.

All very simple, but good enough for this test, the key methods are shown below

1 1: private void IfTest(object sender, ConditionalEventArgs e)

2: {

1 3:       var currentItem = workflowProperties.Item;        e.Result = currentItem.Title.StartsWith("A");

4: }

1 5:  

6: private void TrueTask(object sender, EventArgs e)

1 7:    {

8: var currentItem = workflowProperties.Item;

1 9:       currentItem\["Approved"\] = true.ToString();

10: currentItem.Update();

1 11:    }
2```
3
4I then created a test using the same form I did for WF based testing, I think the comments cover the key points
5
6```
7 1: \[TestMethod\]

2: public void WorkFlowSwitchOnTitle_TitleStartsWithA_SetApprovelField()

1 3:       {

4: using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())

1 5:           {

6: 

1 7:               // Create our fake workflow and items

8: var fakeProperties = Isolate.Fake.Instance(Members.ReturnRecursiveFakes);

1 9:               var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);

10: 

1 11:               var fakeField = Isolate.Fake.Instance<SPField>(Members.ReturnRecursiveFakes);

12: fakeField.DefaultValue = false.ToString();

1 13:               Isolate.WhenCalled(() => fakeProperties.Item).WillReturn(fakeItem);

14: // setup the if test

1 15:               Isolate.WhenCalled(() => fakeItem.Title).WillReturn("ABC");

16: Isolate.WhenCalled(() => fakeItem["Approved"]).WillReturn(fakeField);

1 17:  

18: // setup the workflow handling AutoResetEvent waitHandle = new AutoResetEvent(false);

1 19:               workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)

20: {

1 21:                   // don't put asserts here as will be in the wrong thread

22: waitHandle.Set();

1 23:               };

24: 

1 25:               workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)

26: {

1 27:                   // don't put asserts here as will be in the wrong thread

28: waitHandle.Set();

1 29:               };

30: 

1 31:               // when this is called the constructor is called twice

32: // the first time is for validation for the workflow in this appdomain see http://odetocode.com/Blogs/scott/archive/2006/03/30/3192.aspx

1 33:               // then the real construction is run, the problem is this double run means that the Isolate.Swap.NextInstance

34: // fails as it attaches to the first validation create, not the second real one

1 35:               WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(SharePointWorkflow.Workflow1));

36: 

1 37:               // SO for this reason we only get the swap after the first create has been done

38: Isolate.Swap.NextInstance().With(fakeProperties);

1 39:  

40: // we then recreate the workflow again, this time it has already been validated so

1 41:               // the swap works

42: instance = workflowRuntime.CreateWorkflow(typeof(SharePointWorkflow.Workflow1));

1 43:  

44: instance.Start();

1 45:  

46: waitHandle.WaitOne();

1 47:               // wait for the workflow to complete and then check the method expected were called                Isolate.Verify.WasCalledWithExactArguments(() => fakeItem.Update());

48: Isolate.Verify.WasCalledWithExactArguments(() => fakeItem["Approved"] = "True");

1 49:           }

50: 

1 51:       }
2```
3
4If you try this without the fix TypeMock provided me with, the two verifies will fail, I am told this is due to a threading issue. Interesting that this is SharePoint specific as the same basic method works OK for standard WF workflows.
5
6I also understand this fix will be in the next TypeMock release, I will update this post when I know for sure