Unit Test Test Data
One of the most valuable lessons I learnt whilst doing unit testing with Sitecore projects was to ensure my tests were robust and repeatable. I went through a lot of pain in my earlier projects with brittle tests that as soon as one test failed, all the others would start failing. All this instability was to do with the test data I was using. I had a small amount of test content that I assumed was always in the state I expected. The issue was that if one test failed and didn’t return the data back to the initial state, the other tests would all start failing.
Your unit tests will be much more robust if they create the data they expect at the start of the test then destroy that data at the end. This helps isolate your tests from each other and ensures more repeatable and robust tests. It’s probably naive to assume the content in your CMS right now is exactly as you expect it if it’s been sitting there for a while. There’s nothing like a rogue test trashing your content to really drive home how unstable this approach is.
Depending on what the code under test does will depend on the scope of your test data. For code that only reads the data we can just create the data at the start of our TestFixture
and destroy the data at the end. If you had code that updated content or needed to test many different content structures then you would probably need to create the test data at the start of the individual test itself and destroy it at the end.
Recently when I added unit testing to the EviBlog (WeBlog) shared source module I decided to try out a new idea for creating my test content. Prior to this idea I would just use the Sitecore API to create my content.
The Sitecore API for creating content is very straight forward. Grab your template, find the location in the content tree where you want your new content to be created then add the new item below the existing. Then you can set the fields of the item. All in all I think it’s quite clean code and I really don’t know how you would make it any simpler.
var template = Sitecore.Context.Database.GetTemplate(“mytemplate”);
var parent = Sitecore.Context.Database.GetItem(“/sitecore/content/home”);
var item = parent.Add(“myitem”, template);
item.Editing.BeginEdit();
item[“field”] = “value”;
item.Editing.EndEdit();
But once you start adding lots of items for a more complex content structure you very quickly start drowning in code. Just one quick point on structuring the code of your TestFixture
. Tests are code just like your program. They also benefit from good coding practises including the use of methods to reduce the amount of repeated code. If you find your self commonly copying sections of code and just updating several parameters, then that sounds like you need a method. I’ve often created something similar to the following as part of my tests.
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
var parent = Sitecore.Context.Database.GetItem(“/sitecore/content/home”);
var item = CreateItem(“myitem”, parent);
var child1 = CreateItem(“child 1”, item);
var child2 = CreateItem(“child 2”, item);
}
private Item CreateItem(string name, Item parent)
{
var template = Sitecore.Context.Database.GetTemplate(“mytemplate”);
var item = parent.Add(name, template);
item.Editing.BeginEdit();
item[“title”] = name;
item[“text”] = “some random text”;
item.Editing.EndEdit();
}
This helps with removing clutter from your code.
This above example is fine when you’re only dealing with simple data in the fields and don’t need to insert links and references to other items. It’s still all possible to do that in code, but I was looking for an easier way. I wanted to leverage the Sitecore tools to create the content such as the content editor or even the page editor.
My new idea was to use the content editor to create the test content structure, then grab the XML for the subtree of content and save it in a file. I can then use that XML to recreate the subtree at any time as part of my test.
So first things first, I need to create some test content in Sitecore. I’m sure you know how to do that . Make sure you create your test content under a single root item. This makes things later on much easier.
Now to get the XML for the content. There are so many ways to do this, not to mention there is a method on the Item class to get the XML in code. I find the easiest way to get an item’s XML is to use Revolver or Sitecore Rocks.
In Revolver I can use the GetItem
(gi
) command to get the XML for an item. Passing the recursive parameter (-r
) I can include the items subitems as well. Combine that with the echo
command and I can write that XML directly out to a file.
cd (/sitecore/content/home/test root)
echo -f c:\temp\content.xml < (gi -r)
If you don’t have Revolver you can use the Sitecore Rocks Visual Studio plugin. Just navigate to your content in the Sitecore explorer, right click on your item then select XML and select one of the options to open the XML (and select and copy it), or open the copy XML dialog.
Either way you’ll be able to copy the XML to the clipboard, then create an XML file in your test project and paste the XML content in it.
Make sure you add the XML file to your test project.
Now to create the content from the XML file. This process simply involves grabbing the item to paste the content below, getting the XML content and “pasting” it into the item to have it imported into the content tree. The following code snippet assumes you’re using the codeflood NUnit test runner or some other test runner which runs inside Sitecore and allows you to call the Sitecore API from your test code.
var home = Sitecore.Context.Database.GetItem("/sitecore/content/home");
using (new SecurityDisabler())
{
home.Paste(
File.ReadAllText(
HttpContext.Current.Server.MapPath("~\test data\content.xml")),
false, PasteMode.Overwrite);
}
m_testRoot = home.Axes.GetChild("testroot");
I’m using a SecurityDisabler
above cause my test is running in the context of the live website so my context (by default) will be the web database and extranet\anonymous user.
The testroot
item above would have been defined inside the XML I pasted. Having a single item at the root in your test content makes it much easier to retrieve your test content so you can store local variables of the items to test against and also to cleanup after you finish your test. All I have to do is delete the m_testRoot
item above.
Now I have a known content structure with expected field values I can write my tests against that content, confident in what to expect in the results.
And because the content creation process is now so easy it’s more likely you’ll create other, different content structures to ensure you’re tests cover a wider range of possible content inputs. Happy Testing!
Cool. But for unit testing I’d expect more clear solution where you don’t need to start sitecore at all instead of trying to add test data - do you have experience with mocking Sitecore API?