Unit Testing Using Fakes For MS Dynamics CRM Custom Workflow

We have seen how to write the Unit test for the plugin in the previous blog Unit test for Plugin. Now we will learn how to write the Unit tests for a custom workflow using Fakes.

Writing unit tests can be difficult, time-consuming, and slow when you can't isolate the classes you want to test from the rest of the system. Here are some steps you need to follow and cover your custom workflow code using Unit test methods.

For custom workflow, add Fakes references to your unit test class,

using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Fakes;  
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk.Workflow.Fakes;

In the custom workflow, we have to write input and output parameters and extract the workflow context. Same as we need to extract workflow context, creating organization service using Stub,

/// <summary>
/// Stub IOrganization Service object
/// </summary>
private StubIOrganizationService service = new StubIOrganizationService();

/// <summary>
/// Stub WorkflowContext Service object
/// </summary>
private StubIWorkflowContext workflowContext = new StubIWorkflowContext();

/// <summary>
/// Stub TracingService Service object
/// </summary>
private StubITracingService tracingService = new StubITracingService();

/// <summary>
/// Stub IOrganization Service Factory object
/// </summary>
private StubIOrganizationServiceFactory factory = new StubIOrganizationServiceFactory();

/// <summary>
/// Initialize the code activity
/// </summary>
[TestInitialize]
public void InIt_Code_Activity()
{
    var workflowUserId = Guid.NewGuid();
    var workflowCorrelationId = Guid.NewGuid();
    var workflowInitiatingUserId = Guid.NewGuid();

    this.workflowContext.UserIdGet = () =>
    {
        return workflowUserId;
    };

    this.workflowContext.CorrelationIdGet = () =>
    {
        return workflowCorrelationId;
    };

    this.workflowContext.InitiatingUserIdGet = () =>
    {
        return workflowInitiatingUserId;
    };

    //// ITracingService
    this.tracingService.TraceStringObjectArray = (f, o) =>
    {
        Debug.WriteLine(f, o);
    };

    //// IOrganizationServiceFactory
    this.factory.CreateOrganizationServiceNullableOfGuid = id =>
    {
        return service;
    };

    this.workflowContext.PrimaryEntityIdGet = () =>
    {
        return Guid.NewGuid();
    };

    this.workflowContext.PrimaryEntityNameGet = () =>
    {
        return "invoice";
    };
}

Unit test method to update the account data as per the Inputs values,

/// Update Account
/// </summary>
[TestMethod]
public void CustomWorkflowtest() {
    ////Arrange
    Guid workOrderTypeValue = Guid.NewGuid();
    Guid serviceAccountValue = Guid.NewGuid();
    OptionSetValue contractTypeValue = new OptionSetValue(1);
    DateTime createdOn = DateTime.Today;
    Entity accountEntity = null;
    //// Act
    //// Workflow inputs
    var inputs = new Dictionary < string,
        object > {
        {
            "entityLogicalName",
            "account"
        },
        {
            "recordGuid",
            Guid.NewGuid()
        }
    };
    AccountDataUpdate defaultTeam = new AccountDataUpdate();
    using(ShimsContext.Create()) {
        this.service.RetrieveMultipleQueryBase = (QueryBase query) => {
            var result = new EntityCollection();
            accountEntity = new Entity("account");
            accountEntity.Id = Guid.NewGuid();
            accountEntity["teamid"] = Guid.NewGuid();
            accountEntity["businessunitid"] = new EntityReference("businessunit", Guid.NewGuid());
            result.Entities.Add(accountEntity);
            return result;
        };
    }
    var invoker = new WorkflowInvoker(defaultTeam);
    invoker.Extensions.Add < ITracingService > (() => this.tracingService);
    invoker.Extensions.Add < IWorkflowContext > (() => this.workflowContext);
    invoker.Extensions.Add < IOrganizationServiceFactory > (() => this.factory);
    invoker.Invoke(inputs);
    //// Assert
    Assert.AreEqual("account", accountEntity.LogicalName);
}

I hope using the above code you can easily write unit test code for your custom workflow activity.

Keep learning new things...!!