Plugins Overview

Installing

In order develop and test plugins you’ll need to use Version 2.x of FakeXrmEasy.Plugins package, as it is the version that targets .NET Framework.

Install-Package FakeXrmEasy.Plugins.v9 -Version 2.x 

This will install the plugins package that uses a CRM SDK version v9.x. See Installing for more details about other versions.

That package comes with extension methods that will make it easier to test plugins.

The approach is that you would FakeXrmEasy to provide you with a default PluginExecutionContext, which then you can override based on the plugin logic.

For example, some plugins might fire for multiple messages but do different things based on that message, so you could pass different Message properties for each scenario you want to test.

Plugin Unit Testing

Let’s assume we’re testing the sample FollowupPlugin plugin (you can find the source code here)

public class FollowupPlugin : IPlugin
{
    //Omitted for simplicity, please see the full source code above
}

That plugin could be test with FakeXrmEasy like

using FakeXrmEasy.Plugins;

public class MyFollowUpPluginTests : FakeXrmEasyTestsBase
{
    public MyFollowUpPluginTests() 
    {

    }

    [Fact]
    public void When_the_followup_plugin_is_executed_for_an_account_after_create_it_should_create_a_new_task_with_a_regardingid()
    {
        _context.EnableProxyTypes(Assembly.GetExecutingAssembly()); //Needed to be able to return early bound entities

        //Get a default plugin execution context that will invoke actions against the In-Memory database automatically
        var pluginContext = _context.GetDefaultPluginContext();

        //Set the necessary properties of the pluginExecution context that the plugin will need
        var guid1 = Guid.NewGuid();
        var target = new Entity("account") { Id = guid1 };

        ParameterCollection inputParameters = new ParameterCollection();
        inputParameters.Add("Target", target);

        ParameterCollection outputParameters = new ParameterCollection();
        outputParameters.Add("id", guid1);

        pluginContext.InputParameters = inputParameters;
        pluginContext.OutputParameters = outputParameters;

        //Execute the plugin with the fake PluginExecutionContext            
        _context.ExecutePluginWith<FollowupPlugin>(pluginContext);

        //Assert: The plugin creates a followup activity, check that that one exists
        var tasks = (from t in _context.CreateQuery<Crm.Task>()
                     select t).ToList();

        Assert.True(tasks.Count == 1);
        Assert.True(tasks[0].Subject.Equals("Send e-mail to the new customer."));
        Assert.True(tasks[0].RegardingObjectId != null && tasks[0].RegardingObjectId.Id.Equals(guid1));
    }

}

ExecutePluginWithTarget

This is a specific method overload that doesn’t require passing in a plugin context and it might be useful for plugins that just execute some logic on the Target entity.

If that’s the case, you migh want to use a simpler ExecutePluginWithTarget method.

_context.ExecutePluginWithTarget<FollowupPlugin>(new Account() { Id = Guid.NewGuid() });

Asserting on the Target entity and/or other PluginContext properties

There is one very important aspect to consider.

FakeXrmEasy will automatically update the state of the In-Memory database as long as any of the Create / Update / Upsert / Delete / Associate / Disassociate operations are executed on the service.

This means that, from the point of view of testing or asserting the state after the test execution, you could just query the context to retrieve such state using, for example:

var accountAfter = _context.CreateQuery<Account>().FirstOrDefault();

Assert.Equal("Some name", accountAfter.Name); 

However, that won’t work if the plugin just modifies the Target (or other plugin context properties) without explicitly calling .Update or any of the above service operations internally (and the plugin, in some cases, shouldn’t do that).

For example, if a plugin that runs in the PreOperation step of an Account Create message, and updates some properties of the target account, those changes will be persisted to the database without calling service.Update(), because it is part of the current database transaction.

So how can we then assert on updates of the Target entity?

Simple: we make the assertions against the exact same object reference that was passed into the plugin.

For example:

var accountTarget = new Account() { Id = Guid.NewGuid() };

_context.ExecutePluginWithTarget<FollowupPlugin>(accountTarget);

Assert.Equal("Some name", accountTarget.Name);