For a while I have been trying to write tests for Sharepoint workflows in Isolator (5.2.x). The idea is that for workflows where we are just setting SPlistItem properties we can have automated tests (i.e. no human interaction). However I have been unsuccessful, it seems that I cannot verify that calls have been made within the workflows. I wondered if anyone has an explanation or fix?
So here is my example of the problem. I have a very simple workflow that if the workflow item’s title starts with an ‘A’ it goes down the true branch and sets a property called “Approved” to true from false and update the item.
First I make sure Isolator can create all the items and that if I call the update method directly within my test, Isolator can verify the update method was called. This works as expected and the code is listed below.
[TestMethod]
public void FakeWorkFlowSwitchOnTitle_TitleStartsWithA_SetApprovelField()
{
// Create our fake workflow
var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>(Members.ReturnRecursiveFakes);
var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);
var fakeField = Isolate.Fake.Instance<SPField>(Members.ReturnRecursiveFakes);
fakeField.DefaultValue = false.ToString();
Isolate.WhenCalled(() => fakeProperties.Item).WillReturn(fakeItem);
// the if test
Isolate.WhenCalled(() => fakeItem.Title).WillReturn("ABC");
Isolate.WhenCalled(() => fakeItem["Approved"]).WillReturn(fakeField);
// these are the two lines that should be called in the workflowSwitchOnTitle_TitleStartsWithA_SetApprovelField
fakeItem["Approved"] = true.ToString();
fakeItem.Update();
Isolate.Verify.WasCalledWithExactArguments(() => fakeItem.Update());
Isolate.Verify.WasCalledWithExactArguments(() => fakeItem["Approved"] = "True");
}
If I use a Sharepoint workflow to do the update, the workflow is run from the test and the workflow's logic sets the value of the fake item as expected. However the final verifys, within the test thread, fail saying the calls have not been made. The test logic is as follows:
[TestMethod]
public void WorkFlowSwitchOnTitle_TitleStartsWithA_SetApprovelField()
{
// Create our fake workflow
var fakeProperties = Isolate.Fake.Instance<SPWorkflowActivationProperties>(Members.ReturnRecursiveFakes);
var fakeItem = Isolate.Fake.Instance<SPListItem>(Members.ReturnRecursiveFakes);
var fakeField = Isolate.Fake.Instance<SPField>(Members.ReturnRecursiveFakes);
fakeField.DefaultValue = false.ToString();
Isolate.WhenCalled(() => fakeProperties.Item).WillReturn(fakeItem);
// the if test
Isolate.WhenCalled(() => fakeItem.Title).WillReturn("ABC");
Isolate.WhenCalled(() => fakeItem["Approved"]).WillReturn(fakeField);
using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
// don't put asserts here as will be in the wrong thread
waitHandle.Set();
};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
// don't put asserts here as will be in the wrong thread
waitHandle.Set();
};
// when this is called the constructor is called twice
// the first time is for validation for the workflow in this appdomain see http://odetocode.com/Blogs/scott/archive/2006/03/30/3192.aspx
// then the real construction is run, the problem is this double run means that the Isolate.Swap.NextInstance
// fails as it attaches to the first validation create, not the second real one
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(SharePointWorkflow.Workflow1));
// SO for this reason we only get the swap after the first create has beend one
Isolate.Swap.NextInstance<SPWorkflowActivationProperties>().With(fakeProperties);
// we then recreate the workflow again, this time it has already been validated so
// so the swap works
instance = workflowRuntime.CreateWorkflow(typeof(SharePointWorkflow.Workflow1));
instance.Start();
waitHandle.WaitOne();
}
Isolate.Verify.WasCalledWithExactArguments(() => fakeItem.Update());
Isolate.Verify.WasCalledWithExactArguments(() => fakeItem["Approved"] = "True");
}
The code in the workflow that does the setting of the values is:
private void TrueTask(