19 August 2011

Unit Testing

I a recent post I showed how to unit test CRM 4 plugins. In the post I used Rhino.Mocks to mock the CRM interfaces and MSTest. Since then I've been doing some more "playing" with unit testing and I've stopped using MSTest, now I'm using NUnit instead.

There's a pretty good comparison between MSTest and NUnit on the "Musings of a Bare Bones Coder" blog (http://www.barebonescoder.com/2010/06/mstest-vs-nunit-with-visual-studio-2010-tdd/) so I'm not going into that here. As is said NUnit does suffer in that it has to be run outside of Visual Studio and the author suggests using TestDriven.Net (http://www.testdriven.net/), which is good but I've since found Visual NUnit 2010 which is a freebie on the MSDN Visual Studio Gallery (http://visualstudiogallery.msdn.microsoft.com/c8164c71-0836-4471-80ce-633383031099).

Using Rhino.Mocks, NUnit, and Visual NUnit 2010 seems to be exactly what the doctor ordered in terms of unit testing your code straight from Visual Studio.

I will block with some more details about these tools later.


16 August 2011

Test-Driven CRM 4 Plugin Development

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.

19 July 2011

CRM 4 Out of Memory When Creating Organisation

I ran into a problem when trying to create a new organisation in CRM 4 today. The error that was thrown was: Insufficient memory to continue the execution of the program.

I did the usual of checking the event logs on the CRM Application Server and the SQL server but nothing really jumped out at me. I was then told how to fix it by adding the a new DWORD registry value

1. Open Regedit and navigate to: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters

2. Add a new DWORD value called: MaxTokenSize

3. Enter the following decimal value: 65535.



Note: Changing the registry can be dangerous, take reasonable care and backups! - If you stuff up your machine it's your fault not mine.

12 July 2011

Remove CRM 4.0 IFrame Whitespace

In CRM 4.0 it's often a requirement to display a list view in an IFrame on a form. This is quite a simple task of using the IE Developer Toolbar to determine the URL of the list view and then injecting the URL into the IFrame src property through JavaScript.

However when you do this you may notice that the list view doesn't stretch take up the whole IFrame, it leaves some whitespace around it:



In the past I've used various JavaScript to remove the whitespace and have settled on a method supplied by Andrew Zimmer's blog (http://blogs.inetium.com/blogs/azimmer/archive/2010/01/14/crm-displaying-related-entity-in-iframe-slightly-improved.aspx).

The following method should be called after setting the src value:

function FixStylingInFrameSource(iframeID)
{
// Check the content window's ready state
if (document.getElementById(iframeID).contentWindow.document.readyState != "complete")
{
// Re-run this function in 10 ticks
window.setTimeout(function () { FixStylingInFrameSource(iframeID) }, 2);
}
// Content window is ready
else
{
// Change the background color
document.getElementById(iframeID).contentWindow.document.body.style.backgroundColor = "#eef0f6";
// Remove the left border
document.getElementById(iframeID).contentWindow.document.body.all(0).style.borderLeftStyle = "none";
// Remove padding
document.getElementById(iframeID).contentWindow.document.body.all(0).all(0).all(0).all(0).style.padding = "0px";

// Make the cell the full width of the IFRAME
document.getElementById(iframeID).contentWindow.document.body.all(0).style.width = "102%"

// Show the IFrame
document.getElementById(iframeID).style.display = "block";
}
}


After using this script the IFrame looks a lot nicer:

08 July 2011

CRM 2011 Change SubGrid FetchXML - Updated for rollup 5

Subgrids are new feature to CRM 2011 and allow records that are linked to a record to be shown on the form. By default the linking is limited to records which are related to parent.

I had a requirement to show a list of leads which have the same company name as the current lead. A subgrid seemed to be the way forwards, in CRM 4.0 I'd have added an IFrame displaying an advanced find list, but the limitation of only displaying related records added something of a stumbling block.

With a bit of, unsupported, scripting I managed to work around this issue. Here's how:

1. Add a subgrid to the Lead form showing all leads. Take a note of the subgrid name.

2. Generate the FetchXML that you want to inject into the subgrid (Advanced Find is your friend here).

3. The following JScript method demonstrates changing the FetchXml for a subgrid called "RelatedLeads"


function UpdateSubGrid()
{
var leadGrid = document.getElementById("RelatedLeads");

//If this method is called from the form OnLoad, make sure that the grid is loaded before proceeding //Included extra null check as a rollup 5 fix
if (leadGrid ==null || leadGrid.readyState != "complete")
{
//The subgrid hasn't loaded, wait 1 second and then try again
setTimeout('UpdateLeadSubGrid()', 1000);
return;
}

//Update the fetchXML that will be used by the grid.
var fetchXml = "";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += " ";
fetchXml += "
";
fetchXml += "
";
fetchXml += "
";

//Inject the new fetchXml
leadGrid.control.setParameter("fetchXml", fetchXml);
//Force the subgrid to refresh
leadGrid.control.refresh();
}


4. As a minimum the method can be called from the OnLoad event but it's probably best to call it from the OnChange event of any attributes that are used to generate the FetchXML

11 May 2011

Microsoft Dynamics CRM 2011 Practice Exams

So Microsoft are releasing the exams for Dynamcs CRM 2011, currently there are two availabile:




There will be more to follow so I'll try to keep this page upto date.

In terms of getting ready for the exams there are instructor led and e-learning courses available from Microsoft, or you can find all the information you need from the implementation guide and SDK. However how do you know when you're ready to take the exam, the answer is to take practice exams.

Here is a link to the accelerated ideas web-site which offers free practice exams including for the above CRM 2011 exams. I've not taken the proper exams yet but the practice one seems to be asking the sort of questions that I think will be asked in real life.

CRM 2011 JScript IntelliSense

So I've been messing around with CRM 2011 and one of the big things that I like is the Web Resources. It's much nicer to be able to write JScript in Visual Studio rather than the script window in previous versions of CRM.

The only draw-back that I've found is that you need to remember the syntax for the Xrm.Page object. Well help is at hand from PatrickVerbeeten.com

The page shows a link to a js file which you can reference within your JScript files to get IntelliSense.

Happy JScripting....