2

Fake it! Unit testing Sitecore with NUnit, Moq & Microsoft Fakes

Recently I’ve been updating Fortis to support Sitecore MVC and wanted to write some unit tests, however one of the issues I ran into was that fact Fortis has a huge dependency on the Sitecore context and the classes associated with it. I had already settled upon using NUnit as my test framework and had also decided to use Moq to mock any objects/dependencies. Unfortunately I hit a roadblock when it came to mocking the Sitecore classes, specifically the Item class. Initially I tried to use Moq and construct an Item class but soon ran into the issue that the Item class requires a Sitecore.Database object which in turn needs the context of a config file. This wasn’t feeling right so I decided to look for another solution and here’s where I found Microsoft Fakes!

I strongly suggest reading through the MSDN page but, to put succinctly, the main reason to use Microsoft Fakes is the fact you can make Shims (mocks basically) of any class and any of the methods and properties on those classes. Generating Fakes are really easy, in fact you may have seen the option when right clicking on references and wondered what it was (I did anyway).

MS_Fakes_Option

Using the “Add Fakes Assembly” will create a .fakes XML file in a Fakes folder, which basically just contains information regarding the original assembly. It will then create a new assembly and add it to the references, this assembly will contain all of the “Shim” classes that you’ll use to fake classes.

As an example I’m going to show how to very quickly get up and running with faking the Item class contained in the Sitecore.Kernel. First important part, for a Fakes assembly to be created it has to also create Fakes assemblies of anything referenced by that assembly. Try doing a Fakes assembly on the System reference and you’ll see it will create a mscorlib Fakes reference also. If you just reference the Sitecore.Kernel in your project and try to make a Fakes assembly it will create the .fakes XML file and not a lot else! To get a Fakes assembly of the Sitecore.Kernel you’ll need to also fake the assemblies below. One thing to note is that when adding a Fakes assembly it can take quite a bit of time, which is why I suggest leaving Telerik.Web.UI and Sitecore.Kernel last. I’ve found the Sitecore.Kernel can take a good few minutes to generate so just be patient and it will appear!

  • MS_Fakes_ReferencesComponentArt.Web.UI
  • HtmlAgilityPack
  • ITHit.WebDAV.Server
  • Lucene.Net
  • Mvp.Xml
  • Newtonsoft.Json
  • RadEditor.Net2
  • Sitecore.Logging
  • Sitecore.NVelocity
  • Sitecore.Zip
  • Telerik.Web.UI

Your references should look something like the image on the left.

If you’ve managed to get all the assemblies faked then we can move onto actually faking the Item class! Depending on how much information you need from the Item class will depend on how much you need to fake, although that’s probably obvious :). In my example I wanted the ability to fake not only the direct properties on the Item class but also to fake some fields. I ended up making three helper methods to use in my unit tests which allows me to create a Shim of the Item class.

CreateTestItem

private Item CreateTestItem(string id = null, string name = "Test Item", string templateId = null, FieldCollection fields = null)
{
	Item item = new ShimItem()
	{
		NameGet = () => name ?? "Test Item",
		IDGet = () => new Sitecore.Data.ID(id ?? new Guid().ToString()),
		TemplateIDGet = () => new Sitecore.Data.ID(templateId ?? new Guid().ToString()),
		FieldsGet = () => fields ?? CreateTestFields(),
	};

	new ShimBaseItem(item)
	{
		ItemGetString = fieldName => item.Fields[fieldName].Value
	};

	return item;
}

So just to explain a bit about what’s going on in the method.

	Item item = new ShimItem()

The created Shim classes can be passed as the original class they came from, so it’s best to declare your object as the original class.

		NameGet = () => name ?? "Test Item",

		ItemGetString = fieldName => item.Fields[fieldName].Value

When you add a Fakes assembly it basically generates Shim classes which contain methods and properties which you can then dictate what they do. The Item class has a Name property which is actually a get/set, the ShimItem class exposes two properties which are NameGet and NameSet. In my example I’m telling the ShimItem object to return the name parameter I’ve passed through or if that’s null return some hard coded text. The () represent any parameters that are required for the original classes property/method to run, in this instance there are no parameters. If you look at the ItemGetString you’ll see it requires a field name parameter, we can then use this parameter in the return. In my example I’m accessing the Fields property of my Shim’d item object.

CreateTestFields

private FieldCollection CreateTestFields(List<Field> fields = null)
{
	if (fields == null)
	{
		fields = new List<Field>();

		fields.Add(CreateTestTextField());
	}

	return new ShimFieldCollection()
	{
		ItemGetString = name => { return fields.FirstOrDefault(f => f.Name.Equals(name)); },
		ItemGetID = id => { return fields.FirstOrDefault(f => f.ID.Equals(id)); },
	};
}

As we’re accessing the Fields (FieldCollection class) property of the Item class we also need to create a ShimFieldCollection and tell it what to do whenever we use .Fields[“Some Field”].

CreateTestTextField

private Field CreateTestTextField(string id = null, string name = null, string value = null)
{
	return new ShimField()
	{
		IDGet = () => new Sitecore.Data.ID(id ?? new Guid().ToString()),
		NameGet = () => name ?? "Text Field",
		ValueGet = () => value ?? "Text Field Value",
	};
}

Finally we also need to be able to create Shim’d fields :).

Usage

Now that we’ve got some helper methods which we can use to create our Shims we can now put them into use! Any time you use Shims you must wrap them in a using(ShimsContext.Create()) { }, below is a unit test I’ve written for Fortis.

[Test]
public void CorrectInheritedTemplateForContext()
{
	using (ShimsContext.Create())
	{
		var testItem = CreateTestItem();

		Template templateItem = new ShimTemplate()
		{
			DescendsFromID = id => true,
		};
		ShimTemplateManager.GetTemplateItem = id =>
		{
			return templateItem;
		};

		var contextProvider = new Mock<IContextProvider>();

		contextProvider.Setup(c => c.PageContextItem).Returns(testItem);

		var itemFactory = new ItemFactory(contextProvider.Object);
		var wrappedItem = itemFactory.GetContextItem<IScBaseTemplate>();

		Assert.IsNotNull(wrappedItem);
	}
}

You’ll notice in the example that I’ve done some more Shims, this is because I know that my ItemFactory has a dependency on the TemplateManager class. You can not only say what to return on a specific Shim object but also on any static class methods or properties. In this instance I’m saying an time the TemplateManager.GetTemplate(Item item) method is called return my ShimTemplate object I’ve created.

Finally I’m using Moq (because you can’t Shim interfaces) to create a mock object of the IContextProvider and telling it to return my test item.

Hopefully this helps you get up and running with unit testing your code which had a dependency on Sitecore classes. I’ll post up more examples as and when I write more unit tests!

Jason Bert