I am an advocate of using unit testing wherever possible. This is because it allows repeatable tests to run, usually in a fraction of a second. Using unit tests allows me to be confident that later updates will not affect the current functionality.
One of the issues with unit testing I had with unit testing for Dynamics plugins & coded activities
- I did not want to be performing actions against an instance
because part of the reason the test could fail is if the record the test is expecting to be there has been deleted
- I did not want to test the connection to the platform. The unit tests should just test the code, not the overall platform.
To prevent connecting to an actual instance, we can utilise Mocks.
In this example, I will be using a Mocking Framework called FakeXrmEasy. This is a fantastic framework which allows most (if not all) of Dynamics functionality to be replicated. The website provides good examples of how to use it – but I’ll go through another example in this post.
The plugin that I will be using for this example is simple. It trigger on PreOperation when an Account is created. It will take the name & address1_city fields and concatenate them into another field called new_nameandcity.
The tests that I will run on this plugin are:
- It should work when name and address1_city are provided
- It should throw an exception when address1_city is not provided
In my example, I have created a new Unit Test project (I am using MS Test, but this framework does work with others, like NUnit). Inside the Unit Test project, open NuGet and search for FakeXrmEasy, then install the version that matches your target instance of Dynamics.
Alternatively, you can use the NuGet console to install directly from the command line – the names follow the pattern ‘FakeXrmEasy.version’, for exampleFakeXrmEasy.365.
If you are using the Dynamics 365 Toolkit to generate the plugin structure, then you should see that the plugin constructor accepts secure &
For the unit test framework to be able to access the plugin, another constructor needs to be added which accepts no parameters. I thought that a parameterless constructor had to be added, but Betim Beja has pointed out that he has updated the framework to allow the plugin instance to be created & then passed it to ExecutePlugin.
In this example, I have also added a property which I use to determine if the plugin is being executed by the unit test runner or by the Dynamics system. I have done this to highlight that sometimes your code may need to be modified to run correctly in both environments. In my example, I am running on Create in PreOperation. If the code is executed within Dynamics, then the Update command cannot be called at the end otherwise an exception is shown regarding record not existing. However, if Update
The two unit tests are included below. A sample project has also been uploaded to GitHub.
Account Created Unit Test – Successful
Account Created Unit Test – Exception Thrown
Hopefully you can see how easy unit testing can be when using the FakeXrmEasy framework. Although unit testing can cause a bit more work upfront, it easily pays for itself through reduced bugs being introduced at later dates.
Unit testing will also allow more confidence when refactoring or adding new functionality as you can re-run all of the tests in seconds to make sure none of the previous functionality has changed.
It is important to remember that unit tests need to be maintained overtime. If the functionality is meant to change, then the unit test needs to be updated to include this. You may also forget to test certain scenarios, when this is noticed, the unit tests should be added again. The aim is to have every execution path covered.
In a previous post, I demonstrated using Azure DevOps (was previously named Visual Studio Team Services) pipelines to automated deployment of managed solutions using Dynamics 365 Build Tools. It is possible to integrate unit tests into the pipeline, to prevent deployment of solutions if the unit tests fail. I will cover how to do this in a later blog.