Unit Testing a State Machine Workflow with Delay Activities
The general approach I am using for workflow testing involves a test fixture class for each state in the workflow. TestFixtureSetup creates a workflow runtime and there is a method CreateWorkflowAndMoveToPaidState() which creates a new workflow instance and triggers the various events needed to move it to the state being tested.
This approach allows effective testing of everything in the workflow except the activities including delays. Testing the delayed activities required some small changes to the workflow.
- Add a new event ForceTimerExpiry that can be triggered by the test.
- Add a handler for that event to any state with a timer
The event handler code sets the timeout to zero:
private void handleForceTimerExpiryPaid_Invoked(object sender, ExternalDataEventArgs e)
{
delayComputronUpdate.TimeoutDuration = new TimeSpan(0);
}
Then a SetState activity resets the current state, which will recreate the timer with the new zero timeout.
-
Make sure reinitialisation of the timer will not add a new delay
private void delayComputronUpdate_InitializeTimeoutDuration(object sender, EventArgs e) { // For testing purposes. Since all delays have non-zero defaults, zero 0 means // that the timeout has been reset by the ForceTimerExpiry event. if (((DelayActivity)sender).TimeoutDuration.Ticks == 0) return; if (DateTime.Now.TimeOfDay < Constants.ComputronUpdateTime) { ((DelayActivity)sender).TimeoutDuration = DateTime.Today + Constants.ComputronUpdateTime - DateTime.Now; } else { ((DelayActivity)sender).TimeoutDuration = DateTime.Today.AddDays(1) + Constants.ComputronUpdateTime - DateTime.Now; } }
-
Trigger the ForceTimerExpiry event from a test
[Test]
public void ExpireComputronUpdateTimer_Test()
{
Guid instanceId = CreateWorkflowAndMoveToPaidState();
WorkflowManager.ForceTimerExpiry(runtime, instanceId, 0);
TestEntityHelper.CheckState(runtime, instanceId, null, null, APWorkflowStates.Presented);
}