So here I am getting on the Test-Driven Development bandwagon, so I'm getting on a few stops later than most but it's getting to the destination that counts right?
To start with I thought I'd cut my teeth on a CRM 4 plugin. In this example the plugin doesn't do anything except check the entity that it's being called from but it shows the steps.
As you're probably aware a CRM plugin depends on the CRM web service via the IPluginExecutionContext interface, so for proper unit testing we need to provide a "fake" implementation of the IPluginExecutionContext interface, this is known as "mocking" in automated unit testing.
There are probably different options for mocking but in this example I'm using the Rhino Mocks framework. Rhino Mocks is open source and can be downloaded from:
http://builds.hibernatingrhinos.com/builds/Rhino-Mocks. Google provides loads of tutorials on Rhino Mocks, I'm not going to go into that here.
1. Create a new solution within Visual Studio and add a Class Library Project, this is for the plugin. Lets call it: UnitTestingPlugin
2. Delete the Class1.cs file that gets created by default.
3. Add references to
microsoft.crm.sdk.dll and microsoft.crm.sdktypeproxy.dll.
4. Now right click on the project and add a new Class, lets call it: AccountPlugin.cs.
5. Open the new class and enter the code as follows:
using Microsoft.Crm.Sdk;
namespace UnitTestingPlugin
{
public class AccountPlugin : IPlugin
{
public void Execute(IPluginExecutionContext context)
{
if (context.PrimaryEntityName != "account")
{
throw new InvalidPluginExecutionException("Plugin expects to run against account entity");
}
}
}
}
6. Now lets save the project and add Test project to the solution, we'll call this project UnitTestingPlugin.Test. The naming convention is the name of the main project with .Test at the end.
7. First things first, lets delete UnitTest1.cs which was created automatically.
8. If you expand the references of the test project you'll see that it includes the Microsoft.VisualStudio.QualityTools.UnitTestFramework reference. We also need to add the CRM references; microsoft.crm.sdk.dll and microsoft.crm.sdktypeproxy.dll.
9. Lets we need to add Rhino.Mocks.dll.
10. The reference to add is one back to the UnitTestPlugin project.
11. Now lets add a new class which we'll call; AccountPluginTest.cs.
12. Open the new class and add the following code:
using Microsoft.Crm.Sdk;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
namespace UnitTestingPlugin.Test
{
[TestClass]
public class AccountPluginTest
{
///
/// This test method will ensure that an error is thrown if the plugin is fired from an unexpected record type, i.e. not an account record!
///
[TestMethod]
[ExpectedException(typeof(InvalidPluginExecutionException))]
public void TestWrongEntity()
{
MockRepository mocks = new MockRepository();
IPluginExecutionContext context = mocks.StrictMock();
DynamicEntity target = new DynamicEntity();
target.Properties["firstname"] = "James";
target.Properties["lastname"] = "Sullivan";
PropertyBag inputParameters = new PropertyBag();
inputParameters.Properties[ParameterName.Target] = target;
using (mocks.Record())
{
Expect.Call(context.InputParameters).Return(inputParameters).Repeat.Any();
//Set the PrimaryEntityName property to something other than account.
Expect.Call(context.PrimaryEntityName).Return("contact").Repeat.Any();
}
using (mocks.Playback())
{
IPlugin plugin = new AccountPlugin();
plugin.Execute(context);
}
}
///
/// This test will ensure that no error is thrown if the plugin is fired from an account record.
///
[TestMethod]
public void TestAccountEntity()
{
MockRepository mocks = new MockRepository();
IPluginExecutionContext context = mocks.DynamicMock();
PropertyBag inputParameters = new PropertyBag();
DynamicEntity target = new DynamicEntity();
target.Properties["name"] = "Orville Consulting Ltd";
inputParameters.Properties[ParameterName.Target] = target;
using (mocks.Record())
{
Expect.Call(context.InputParameters).Return(inputParameters).Repeat.Any();
Expect.Call(context.PrimaryEntityName).Return("account").Repeat.Any();
}
using (mocks.Playback())
{
IPlugin plugin = new AccountPlugin();
plugin.Execute(context);
}
}
}
}
13. Finally we're ready to run our test. From the Visual Studio menu bar select Test --> Run --> Tests in Current Context.
You should get two passes, as shown in the following screenshot:
Hopefully over the next day or so I'll blog an example of automated unit-testing CRM 2011 plugins.