Create a Unit Test for a Plugin

In this sample I am going to be testing a sample plugin "PreAccountCreate". This plug-in has been written using the CRM Developer Toolkit. The main purpose of this plug-in is to generate an account number every a new account is created in CRM. The number must be prefixed a string that the plug-in retrieves from another configuration entity in CRM. This plug-in fires on the "PreOperation" stage of the "Create" message in the pipeline.

For reference the main logic of the plugin below.

PreAccountCreate.cs code:
        protected void ExecutePreAccountCreate(LocalPluginContext localContext)
        {
            if (localContext == null)
            {
                throw new ArgumentNullException("localContext");
            }

            if (localContext == null)
                throw new ArgumentNullException("localContext");

            localContext.TracingService.Trace("Getting new contact from context");
            Entity entity = null;
            if (localContext.PluginExecutionContext.InputParameters.Contains("Target") &&
            localContext.PluginExecutionContext.InputParameters["Target"] is Entity)
                entity = ((Entity)localContext.PluginExecutionContext.InputParameters["Target"]);

            else
                throw new InvalidPluginExecutionException("Entity record was not found as Target in Plugin Context");

            QueryByAttribute query = new QueryByAttribute()
            {
                ColumnSet = new ColumnSet("xdft_value"),
                EntityName = "xdft_configuration",
                Attributes = { "xdft_name" },
                Values = { "AutoNumberPrefix" }
            };

            EntityCollection entities = localContext.OrganizationService.RetrieveMultiple(query);

            if (entities.Entities.Count == 0)
                throw new InvalidPluginExecutionException("'AutoNumberPrefix' configuration record couldn't be found");
            else if (entities.Entities.Count>1)
                throw new InvalidPluginExecutionException("More than one configuration record was found with name 'AutoNumberPrefix'");

            var prefix = entities.Entities[0].Contains("xdft_value")? entities.Entities[0]["xdft_value"]: null;
            if (prefix != null)
                entity.Attributes.Add("xdft_reference", prefix + new Random(1).Next(10000000, 20000000).ToString());
         
            localContext.PluginExecutionContext.InputParameters["Target"] = entity;
        }

As you can see there is quite a few dependencies on the CRM runtime in this plug-in that we will have to fake to be able to test the logic in isolation. The main dependencies are:
  • Extraction of the runtime services from the context (tracing, factory, etc...)
  • Retrieve and update the target image of the account form the context
  • retrieve the prefix from the configuration entity using the CRM service

so let's get started and see how we can do this using the xRM Test Framework. You should have already completed the steps to setup a Unit Test project by now.

So the first thing to do is add a plug-in unit test project to your template using the provided template.

To create this test, just follow the next steps:
  • Right click on the folder Plugins of the Unit Test project
  • Add new Item
  • Dynamics CRM => "Plugin Unit Test using Fakes"

xRMTestFramework_AddPluginUnitTestUsingFakes.png

This should generate the skeleton for your Unit Test.

Instance Variables

This is where you place your global variables that you want to re-use across setup and verification. In this instance I am just going to declare a test prefix that would have been otherwise retrieved from CRM.

        #region Instance Variables

        //TODO: Declare your variables for setup and verification
        private string _prefix = "TestPrefix";

        #endregion

Setup

This is where you have fake an external dependencies that the plug-in has. This includes the CRM runtime. This includes the plug-in context and any calls it will make to the CRM or external services. The idea is that this test should only be focusing on the logic of the plug-in assuming all external dependencies are working as expected.

Note the framework does most of the ground work for you. This includes setting up a Fake Context and hooking up all the services together. These are made available to you via properties and methods from the base class.

First thing let the framework know the context of your plugin.

            //TODO: Setup your trigger
            base.SetPluginEvent("account", "Create",
               Xrm.Framework.Test.Unit.SdkMessageProcessingStepImage.PreOperation);

Next as you know the plug-in retrieves a configuration value from CRM. So in your setup you need to fake that call and retrieves a static value instead.

            base.OrganizationServiceStub.RetrieveMultipleQueryBase = (query) =>
            {
                EntityCollection entities = new EntityCollection();

                if (query is QueryByAttribute)
                {
                    Entity config = new Entity("xdft_configuration");
                    config["xdft_value"] = _prefix;
                    entities.Entities.Add(config);
                }
                return entities;
            };

Next the plug-in access the target to be able to set the new account number. So generate a fake target object. Note that I don't need to provide all the properties. I only need to fake what the plug-in is going to use.

            base.OrganizationServiceStub.RetrieveMultipleQueryBase = (query) =>
            {
                EntityCollection entities = new EntityCollection();

                if (query is QueryByAttribute)
                {
                    Entity config = new Entity("xdft_configuration");
                    config["xdft_value"] = _prefix;
                    entities.Entities.Add(config);
                }
                return entities;
            };

Finally return a instance of the plugin that you want to test to the framework.

            IPlugin plugin = new PreAccountCreate();

            return plugin;

Now are done with the setup phase.

Test

The framework takes care of hooking up the CRM runtime and executing your plug-in. So you don't need to do anything in this step.
        #region Test

        [TestMethod]
        public void RunTestAutoNumberXrmUsingStubs()
        {
            base.Test();
        }

        #endregion

Verify

This is the most important phase where you get a chance to confirm whether your plugin is behaving as expected. An Error property is available in the base class that will contain any error that your plug-in has thrown. Note in some cases such as validation plug-in you might actually want this to contain a valid error exception.

In this instance I am going to extract the target after the execution of the plug-in and verify that my plug-in has actually update this with an account number containing the right prefix.

        #region Verify

        protected override void Verify()
        {
            Assert.IsNull(Error);

            Entity modifiedTarget = (Entity)base.GetTarget();

            string reference = modifiedTarget["xdft_reference"].ToString();

            Assert.IsTrue(reference.Contains(_prefix));
        }

        #endregion

This concludes the Unit Test. You should be able now to run the unit test successfully and setup breakpoints in your plug-in too how it is working.

The complete TestAutoNumberXrmUsingStubs.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Xrm.Framework.Test.Unit.Fakes;
using Microsoft.Xrm.Sdk.Query;
using Xrm.Solutions.FrameworkSample.Plugins;


namespace Xrm.Solutions.FrameworkSample.XrmUnitTests.Plugins
{
    [TestClass]
    public class TestAutoNumberXrmUsingStubs : PluginUnitTest
    {
        #region Instance Variables

        //TODO: Declare your variables for setup and verification
        private string _prefix = "TestPrefix";

        #endregion

        #region Setup

        protected override IPlugin SetupPlugin()
        {
            //TODO: Setup your trigger
            base.SetPluginEvent("account", "Create",
               Xrm.Framework.Test.Unit.SdkMessageProcessingStepImage.PreOperation);

            //TODO: Setup your Stubs & Shim
            base.OrganizationServiceStub.RetrieveMultipleQueryBase = (query) =>
            {
                EntityCollection entities = new EntityCollection();

                if (query is QueryByAttribute)
                {
                    Entity config = new Entity("xdft_configuration");
                    config["xdft_value"] = _prefix;
                    entities.Entities.Add(config);
                }
                return entities;
            };

            base.SetTarget(new Entity("contact"));

            //TODO: Create your Plugin
            IPlugin plugin = new PreAccountCreate();

            return plugin;
        }

        #endregion

        #region Test

        [TestMethod]
        public void RunTestAutoNumberXrmUsingStubs()
        {
            base.Test();
        }

        #endregion

        #region Verify

        protected override void Verify()
        {
            Assert.IsNull(Error);

            Entity modifiedTarget = (Entity)base.GetTarget();

            string reference = modifiedTarget["xdft_reference"].ToString();

            Assert.IsTrue(reference.Contains(_prefix));
        }

        #endregion
    }
}

Last edited Jun 26, 2014 at 10:41 AM by waelhamze, version 3

Comments

rbasten Feb 4, 2016 at 9:31 AM 
Hi,

I've followed all the steps. but when I start the tests, I recieve the error that it requires fakes dll version 11. I'm running Visual Studio 2013 which has version 12. I've tried setting the specific version to false but that doesn't help.
Can you help we with this?

kyklovod Aug 3, 2015 at 11:49 AM 
Hi
Can and how I test Plugins with Post/Pre images ?

Katarsys Jan 15, 2015 at 12:22 PM 
why this is necessary?

base.OrganizationServiceStub.RetrieveMultipleQueryBase = (query) =>
{
EntityCollection entities = new EntityCollection();

if (query is QueryByAttribute)
{
Entity config = new Entity("xdft_configuration");
config["xdft_value"] = _prefix;
entities.Entities.Add(config);
}
return entities;
};

I tried without this, and my code works fine, I don'r really know what this code do, can you give me some extra information?

My code:

base.SetPluginEvent("account", "Create",
Xrm.Framework.Test.Unit.SdkMessageProcessingStepImage.PreOperation);

Entity entidadPrueba = new Entity("Account");
entidadPrueba.Attributes["name"] = "PEPE";

base.SetTarget(entidadPrueba);
//TODO: Instanciamos el Plugin que queremos depurar
IPlugin plugin = new AccountPreCreate();

return plugin;

aatoledano Nov 18, 2014 at 2:52 PM 
I think there may be an error on this tutorial, there's a duplicated block on Setup section, the second
base.OrganizationServiceStub.RetrieveMultipleQueryBase....
could be just:
base.SetTarget(new Entity("contact"));