Question

I'm trying to unit test a Workflow Service by using Microsoft.Activities.UnitTesting The goal is to mock the service's extensions in order to ensure that all steps are executed.

The mock objects don't seem to get called even though the extensions are registered in the Host. As expected, if the extensions are not registered an exception is thrown.

        WorkflowServiceTestHost host = null;

        try
        {
            Mock<ISubscriber> publisher = new Mock<ISubscriber>();
            Mock<IWebWorker> webWorker = new Mock<IWebWorker>();

            var voucher = new Voucher();

            using (host = new WorkflowServiceTestHost(workflowServiceFile, serviceAddress))
            {
                host.WorkflowExtensions.Add<ISubscriber>(() => publisher.Object);
                host.WorkflowExtensions.Add<IWebWorker>(() => webWorker.Object);

                host.Open();
                using (var factory = new ChannelFactory<IServiceInterface>(clientBinding, serviceAddress))
                {
                    var proxy = factory.CreateChannel() as IServiceInterface;

                    proxy.Process(voucher);
                }
            }

            **//These validations fail...**

            publisher.Verify(m => m.Push(It.IsAny<Voucher>()), Times.Once(), "ISubscriber.Push was not called.");
            webWorker.Verify(m => m.Done(It.IsAny<Voucher>()), Times.Once(), "IWebWorker.Done was not called.");

            // The host must be closed before asserting tracking
            // Explicitly call host.Close or exit the using block to do this.
        }
        finally
        {
            if (host != null)
            {
                host.Tracking.Trace(TrackingOptions.All);
            }
        }

The workflow runs as expected in IIS.

Thanks!

Edit: This error is being written in the Workflow Host output:

WorkflowInstance "Sequential Service" Unhandled Exception Source "Receive Process Message" 
Exception <System.NotSupportedException: Expression Activity type 'CSharpReference`1' requires compilation in order to run.  
Please ensure that the workflow has been compiled.
at System.Activities.Expressions.CompiledExpressionInvoker.InvokeExpression(ActivityContext activityContext)
at Microsoft.CSharp.Activities.CSharpReference`1.Execute(CodeActivityContext context)
at System.Activities.CodeActivity`1.InternalExecuteInResolutionContext(CodeActivityContext context)
at System.Activities.Runtime.ActivityExecutor.ExecuteInResolutionContext[T](ActivityInstance parentInstance, Activity`1 expressionActivity)
at System.Activities.OutArgument`1.TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance targetActivityInstance, ActivityExecutor executor)
at System.Activities.RuntimeArgument.TryPopulateValue(LocationEnvironment targetEnvironment, ActivityInstance targetActivityInstance, ActivityExecutor executor, Object argumentValueOverride, Location resultLocation, Boolean skipFastPath)
at System.Activities.ActivityInstance.InternalTryPopulateArgumentValueOrScheduleExpression(RuntimeArgument argument, Int32 nextArgumentIndex, ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Boolean isDynamicUpdate)
at System.Activities.ActivityInstance.ResolveArguments(ActivityExecutor executor, IDictionary`2 argumentValueOverrides, Location resultLocation, Int32 startIndex)
at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)>
Was it helpful?

Solution

I've just realized WorkflowServiceTestHost is a Microsoft.Activities.UnitTesting class and not yours.

So, let's see if this is possible. As I saw on its source code you can pass to the constructor the WorkflowService's object itself instead of the XAMLX file. Something like this:

// Load WorkflowService from .xamlx
// Actually this is the method WorkflowserviceTestHost uses when you pass a
// .xamlx so we're taking a step back to be able to compile the body
var wfService = XamlServices.Load("c:\\workflowservice.xamlx") as WorkflowService;

// Compile workflow body
CompileExpressions(wfService.Body);

// Now you can use WorkflowServiceTestHost
using (host = new WorkflowServiceTestHost(wfService, serviceAddress))
{
    // ... do your thing
}

CompileExpressions is taken from the link that I gave you earlier.


That being said, it seems odd consider testing a WCF service as unit-testing. Unit tests should be focused on small activities of your service, those are truly unit-testable. Integration tests (or functional tests) is where you test services with all its dependencies (IIS\WAS, network, DBs, etc).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top