Next level TDD for Microsoft Dataverse with XrmMockup

There are many ways of writing business logic for Microsoft Dataverse and a single error in one can take down an entire system. In this post I will show you

Latest Post Value-based triggers by Magnus Gether Sørensen public

There are many ways of writing business logic for Microsoft Dataverse and a single error in one can take down an entire system. In this post I will show you a mocking framework that has the potential to ensure that will never happen.

In its simplicity, XrmMockup is like the other mocking frameworks that exists for Microsoft Dataverse. It is free and open-source. You get an IOrganizationService and you call that as if you were calling the API of your actual Microsoft Dataverse instance. Using this you can write a test that makes the same calls you would in your business process.

The difference between each mocking framework is what it does on the inside. They all aim to test your plugins in some capacity, but XrmMockup attempts to test your entire Microsoft Dataverse instance. That would seem like an impossible task, but getting most of the way there will ensure a better development experience than writing logic blindly. Later I will show just how far we are now.

The history of XrmMockup

If you don't care about me or how the tool came to be, then skip this paragraph :)

In 2016 I was a student developer and a recent hire at Delegate. After about a month of playing around with Dynamics CRM resulting in a simple tool, I was assigned a pet project of a coworker - merely a single .cs file and an idea at the time. The file could load plugin assemblies and call their execute method. The idea was to point to a CRM instance, get all the things you need to mimic it, and then run a local CRM on your computer. This would allow you to debug your plugins, but also debug when a plugin calls a plugin, when a plugin calls a workflow that calls a plugin and so on.

After 6 months XrmMockup could mimic a simple pipeline. The next step was to write an interpreter for workflows. They have a simple xaml structure that allowed me to deserialize the implementation, turn it into an abstract syntax tree and evaluate that. 3 months later XrmMockup could interpret simple workflows and run them as part of the transaction pipeline.

XrmMockup is much more now, but let me show you how to use it.

Using XrmMockup

First you install the nuget package for your environment, XrmMockup365 if you are in the cloud. After that you follow the setup instructions on GitHub

After following the setup you will have a structure that looks similar to this.

File structure after calling the metadata generator

Now you have everything XrmMockup needs on your machine and you are ready to write some tests. In true TDD style we start by writing a failed test. Notice that all this test does is interact with the IOrganizationService (in this example called orgService). The early-bound framework used is XrmContext.

public void TestPrimaryContactIsCreated()
    using (var context = new Xrm(orgService))
        var acc = new Account();
        acc.Id = orgService.Create(acc);

        var retrieved = context.AccountSet.Where(x => x.AccountId == acc.Id).FirstOrDefault();
        var primaryContact = context.ContactSet.Where(x => x.ContactId == retrieved.PrimaryContactId.Id).FirstOrDefault();

We currently have no plugin that creates a primary contact for an account when it is created, so this test fails. So we create the following plugin.

public class AccountPrimaryContactPlugin : Plugin {

    public AccountPrimaryContactPlugin() : base(typeof(AccountPrimaryContactPlugin)) { }

    protected void Execute(LocalPluginContext localContext) {
        // get service from context
        var service = localContext.OrganizationService;

        // create new account
        var contact = new Contact();
        contact.Id = service.Create(contact);

        // set as primaryContact
        var acc = new Account(localContext.PluginExecutionContext.PrimaryEntityId);
        acc.PrimaryContactId = contact.ToEntityReference();

We could register this plugin in our Microsoft Dataverse instance, run the metadata generator again, and the test will succeed. However, XrmMockup supports in memory plugin registration. At the moment only DAXIF's plugin registration is supported, which is added to the plugin like this.

public class AccountPrimaryContactPlugin : Plugin {

    public AccountPrimaryContactPlugin() : base(typeof(AccountPrimaryContactPlugin)) { 

    protected void Execute(LocalPluginContext localContext) {

By using XrmMockup we have written our business logic in a plugin. We know it works because we used TDD. All of this without calling our actual Microsoft Dataverse instance.

If you run this test you will realize that it runs very fast. XrmMockup uses itself to test whether it works, and on my laptop I can run over 1200 tests in parallel in under 30 seconds.

There are two alternatives styles to XrmMockup. Unit test style frameworks like FakeXrmEasy and UI test style frameworks like EasyRepro. FakeXrmEasy will be fast like XrmMockup, but only focuses on plugins. EasyRepro will do far better at testing against your Microsoft Dataverse instance, but will be much slower - in my opinion so slow it will not work for TDD. That is why XrmMockup is perfect for TDD, fast but close to your actual instance.

The Future

XrmMockup can do a lot of things. The list currently looks like this

For examples of all these features I refer to the wiki

As I said in the beginning, the goal is to support every way of writing business logic for Microsoft Dataverse. In the near future the goal is to expand the support for actions and custom API definitions. Another feature on the horizon is to support calling Power Automate Cloud Flows locally.

If you want to hear more about XrmMockup and see it live in action - join me at the Scottish Summit!

Magnus Gether Sørensen

Published 2 years ago