Tuesday, July 29, 2008

TDDing a CRM 4.0 Plugin - Part 6

One thing that I haven't touched on so far is the testing of a read from the CRM WebService. We've sent it a record to update, but we haven't read from it yet.

There are a few different approaches you can take to this:



  1. Use a plugin that serializes the DynamicEntity in the Image PropertyBags to write to a file. You can then deserialize that file in test cases and use that as your sample objects. The downside to this is that you can only do this for DynamicEntity classes since that's all that is available in the plugins. If you are working with "core" objects, this does you no good.


  2. Create your own sample objects from scratch. This can be very tedious (less so if you're working with core objects, which I don't recommend) and prone to errors as it's likely you'll use the wrong Property type with the wrong attribute (LookupProperty with the "owner" attribute).


  3. Use an Object Builder/Mother to create random objects at runtime. The problem here is that we're talking "random" and that's usually not good unless you want to put significant coding behind making them "smart random". In which case, why not just write the samples from scratch.




The #1 approach is my favorite as it makes for less coding and more realiable objects. However, it means that anytime you want to retrieve objects from the CRM WebService you can't use the standard Retrieve and RetrieveMultiple commands as they return "core" objects by default.

#2 is pretty straight forward and we've already done it before:


DynamicEntity account = new DynamicEntity("account");
account["accountid"] = new Key(Guid.NewGuid());
account["accountnumber"] = "someAccountNumber";
account["name"] = "accountName";


#3, well, I don't even want to get into that. Have fun with it though. =-}

Creating a plugin that will serialize your objects is pretty easy:


public class SerializeEntityPlugin : IPlugin
{
public void Execute(IPluginExecutionContext context)
{
DynamicEntity entity = (DynamicEntity) context.PostEntityImages["PostImage"];
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DynamicEntity));
xmlSerializer.Serialize(new StreamWriter(@"c:\temp\" + GetFilename(entity), false), entity);

}

private string GetFilename(DynamicEntity entity)
{
foreach (Property property in entity.Properties)
{
if (property.GetType() == typeof(KeyProperty))
{
return entity.Name + "--" + ((KeyProperty) property).Value.Value + ".xml";
}
}
string returnValue = entity.Name + "--Unknown Primary Key.xml";
return returnValue;
}
}



Register this against an account and it's update event and then update an account through the UI (make sure the "C:\temp" directory exists). You should get a file called "account--.xml".


Now we've got a serialized DynamicEntity object. We can deserialize this object and use it in our tests. To do that, first copy the resulting file to your solution. Make sure you setup the file to be copied to your output directory so that it's easily available during the runtime of the tests (I would also suggest renaming the file to not include the GUID so that you don't have to worry about it when referencing the filename).


public DynamicEntity GetSampleAccount()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof (DynamicEntity));
return (DynamicEntity) xmlSerializer.Deserialize(new StreamReader(@"Sample Files\account.sample.xml").BaseStream) ;
}


You could also refactor this out or create a wrapping method to get a variety of different objects for your testing.

In the end, I recommend both techniques (not the 3rd one). You can get a long way with just creating your own objects but if your code depends on all the various CRM value types (Picklist, Lookup, CrmDateTime), then it can be pretty tedious to create the testing objects, whereas this is pretty simple if you don't mind a little plugin deployment.

=-}

No comments: