codeflood logo

Mocking Sitecore

Whenever I talk about unit testing and Sitecore, someone inevitably will ask about the practise of mocking. Mocking involves creating a simple object to replace a dependency in your unit tests so your test code doesn’t have to invoke that dependency. The issue I’ve had with mocking is that you have to deeply understand the object you’re mocking or your mocks won’t be a reflection of the dependency being mocked and your test will be useless.

Recently I was prompted to dive head first into mocks and investigate how I could mock Sitecore. This prompt was the first official Sitecore book “Professional Sitecore Development” which I can finally and proudly say I was a part of. After Dreamcore last year John West (CTO of Sitecore and author of the book) contacted me and asked if I could write a chapter for the book on testing, which I did.

My initial draft of the chapter (in fact, right up until the final submission to John) didn’t include mocking, but a reviewer of the chapter (Fellow Sitecore MVP Klaus Petersen) suggested I include mocking. Ultimately I thought “who am I to hold back this potentially powerful technique, just because I have concerns about it’s application?”. I mean, I wrote Revolver which used improperly could probably do a fair amount of damage to any Sitecore install (working directly on raw field values which could cause the UI tools to break). The reason I named Revolver as such was because it was dangerous. “Here’s Revolver, now don’t shoot yourself in the foot”. The same can be said about C and C++. You wanna cast that object to an incompatible type? Go ahead!

So I came to the conclusion that I should stop ignoring this technique and dive head first into it.

Now, this content didn’t end up making it into the book. I got it to John a little too late and there wasn’t enough time for it to go through the appropriate approval and editorial processes. So below is a slightly altered version of the content that didn’t make it in time for the book.

Introduction to Mocking

Mocking frameworks such as Moq (http://code.google.com/p/moq/)) and Rhino Mocks (http://hibernatingrhinos.com/open-source/rhino-mocks ) can be used to create fake versions of objects during testing and orchestrated to behave as required to allow the test to run. The more popular open source mocking frameworks allow creating instances of an interface or class and providing an implementation for any virtual methods. The Moq framework will be used as the mocking framework in this post.

The steps required to create a mock object using Moq are as follows:

  1. Create a new instance of the Mock object passing it the type to mock.
  2. Define how each call of the object (method call, property access) should behave and any data returned.
  3. Retrieve the mocked object from the Mock instance and use it in the test code.

The following code sample shows creating a mock of a ficticous IData interface.

// Create an instance of the Mock class to create a mocked IData instance 
var mock = new Mock<IData>();

// Set how the mocked object should behave 
// Setup mocked object to return 1 when "code1" is passed to the GetCount()
  method 
mock.Setup(m => m.GetCount("code1")).Returns(1);

// Setup mocked object to return 2 when "code2" is passed to the GetCount()
  method 
mock.Setup(m => m.GetCount("code2")).Returns(2);

// Setup mocked object to return "data" when the name property is retrieved 
mock.SetupProperty(m => m.Name, "data");

// Retrieve the mocked object 
var dataObject = mock.Object;

// Use the mocked object in tests 
Assert.AreEqual(1, dataObject.GetCount("code1"));
Assert.AreEqual("data", dataObject.Name);

In the above code an instance of the Mock class is first created, passing the type that must be mocked. The next 2 lines tell the mock object what to return when the GetCount() method is called with various different parameters. Then the Name property is setup to return the value “data” when retrieved. Finally the configured object is retrieved from the Mock and then used in the assertions.

A Word of Warning

When you mock a component, you are codifying many assumptions about how that component works and your understanding of how that component works. In a bespoke developed system where mocking is used to allow components to be developed ahead of their dependent components the mocks would typically be developed against a specification or common understanding of how the component being mocked should behave. And if at the end of development the component being mocked does not behave as expected it can be modified until it does. This is not the case with an external system such as Sitecore.

When you mock Sitecore components, you’re codifying those same assumptions about how the component works and your understanding of it, but if your assumptions are wrong you have no control to change Sitecore and make it work the way you thought it should. Your custom components have now been tested under false assumptions and may be harbouring bugs, which are hidden behind the incorrect mocks.

Consider Sitecore query. What would the following code return?

var items = Sitecore.Context.Item.Axes.SelectItems("../my-item");

Many developers would say the sibling of the current context item named “my-item” would be returned in the above code. Actually, the above code will throw a Sitecore.Data.Query.ParseException exception because the dash in the name wasn’t escaped. The query parsing engine is interpreting the dash as an operator instead of a name character.

This is the danger of mocking an external system. If you’re not aware of every facet of the component being mocked you risk creating mock objects which aren’t true representations of the components they mock, and the components being tested using these mocks may still contain bugs.

Mocking Sitecore Objects

Moq (and other mocking frameworks) can only create mock objects for interfaces and virtual methods on concrete classes. Unfortunately Sitecore version 6.5 and before doesn’t make use of interfaces or virtual methods for most of the objects which would need to be mocked during a testing scenario. (Sitecore 7 adds many interfaces that will greatly help in this regard.)

One technique which facilitates this kind of mocking is to update the code under test to use a different class which can be mocked, rather than the Sitecore types directly. This class can expose the same API as the Sitecore object, and pass the calls through to a wrapped Sitecore object. This kind of technique is referred to as the wrapper or adapter pattern. The adapter pattern is a software design pattern which allows wrapping one class to allow it to be compatible with another when it normally wouldn’t be. In this case the Sitecore API doesn’t need to change though the methods and properties being used in the test need to be virtual so the mocking framework can orchestrate a mocked version of the class. The methods and properties of the adapter (which copies the same API as the Sitecore component) would simply call the corresponding method or property on the wrapped Sitecore object.

The following utility method accesses fields of a Sitecore item and returns the data required. This method is going to be tested using mocks.

public static string GetTitle(Item item) 
{ 
  var fieldTitle = item["title"]; 

  if (string.IsNullOrEmpty(fieldTitle)) 
    fieldTitle = item.Name;

  return fieldTitle; 
}

To easily test the above code a mocked version of Sitecore.Data.Items.Item would be passed into the method, but because Sitecore.Data.Items.Item doesn’t implement any interfaces and the field properties aren’t virtual, Moq cannot create a mocked object for the parameter.

Instead, an adapter can be created to wrap the Sitecore.Data.Items.Item and make the methods virtual to allow Moq to create a mocked object for the tests. The following class shows an adapter which could be used in the previous utility method in place of the Sitecore.Data.Items.Item instance.

public class ItemAdapter 
{ 
  private Sitecore.Data.Items.Item m_item = null;

  public ItemAdapter() 
  { 
  }

  public ItemAdapter(Sitecore.Data.Items.Item item) 
  { 
    m_item = item; 
  }

  public virtual string this[string name] 
  { 
    get 
    { 
      return m_item[name]; 
    } 
  }

  public virtual string Name 
  { 
    get 
    { 
      return m_item.Name; 
    } 
  } 
}

In the above class, only the required properties have been implemented, after all, if a method or property isn’t required then there’s no need to add it to the adapter. Note also how each property is virtual which will allow Moq to create a mock object of this type for the tests. The parameterless constructor is also required to allow Moq to create instances of the adapter.

This adapter can now be used in place of a Sitecore.Data.Items.Item in the utility method.

public static string GetTitle(ItemAdapter item) 
{
  var fieldTitle = item["title"];

  if (string.IsNullOrEmpty(fieldTitle)) 
    fieldTitle = item.Name;

  return fieldTitle; 
} 

Comparing the above implementation of the GetTitle() method using the adapter to the previous implementation using the concrete Sitecore.Data.Items.Item class, the only thing that needs to change is the type of the parameter. This is because the adapter is doing it’s job, by copying the interface of the class it acts as an adapter for. However the calling code needs to be updated to pass an instance of the adapter rather than a Sitecore.Data.Items.Item.

var title = ItemUtil.GetTitle(new ItemAdapter(item));

The GetTitle() method can now be tested using mock objects instead of real Sitecore objects.

Before Moq can be used in the test project, it must be added.

  1. Download the latest release of Moq from http://code.google.com/p/moq/downloads/list
  2. Extract the Moq.dll assembly for the .net version being used from the downloaded archive and place the assembly in the lib folder of the test project.
  3. Add a reference to the Moq.dll assembly to the test project.

Now tests can be written for the utility method making use of mocks.

[NUnit.Framework.Test] 
public void GetTitle() 
{ 
  var mock = new Mock<ItemAdapter>();
  mock.SetupGet(m => m["title"]).Returns("the title");

  var title = ItemUtil.GetTitle(mock.Object); 
  Assert.AreEqual("the title", title); 
}

In the above test method a mock is created for the ItemAdapter class. The mock is then configured to return a specific field value when the title field is accessed. The mocked object is then used in the method under test and the outcome asserted.

The above test will now run completely in memory without the need for Sitecore’s configuration or to connect to a physical database engine. Tests using the above technique will as a result run much faster than the techniques I’ve shown previously:

The downfall is you have to wrap all calls to the Sitecore API.

However, the adapter classes created can be written once and reused on other projects. They only need to be updated when the Sitecore API is updated.

Isolating Sitecore

If one can accept the risk of mocking Sitecore components, the above mocking technique only has one drawback; it requires all calls to the Sitecore API to be wrapped in adapter objects to allow a mocking framework to mock the adapter. There is another class of mocking frameworks which allow mocking all objects, not just interfaces or virtual methods. These frameworks are called isolation frameworks.

Isolation frameworks typically tap into core pieces of the CLR (Common Language Runtime) to orchestrate and fake any object. Two popular isolation frameworks are Moles from Microsoft Research (http://research.microsoft.com/en-us/projects/moles/)) and Typemock Isolator (http://www.typemock.com/isolator-product-page).

I tried my hand at using Moles but ran into issues trying to mock field access on a Sitecore item. I was quite happy to see the Compiled Domain Model project from the Sitecore shared source library was using Moles in some tests. The Compiled Domain Model project uses Moles to mock Items but it doesn’t look like the tests access field values, so Moles works fine for these tests.

Typemock Isolator can be used in much the same way as Moq above, but it can mock a Sitecore.Data.Items.Item instance and not just interfaces and virtual methods.

To add Typemock Isolator to the test project:

  1. Download the latest version of Typemock Isolator .NET from http://www.typemock.com/download/.
  2. Install Typemock Isolator following the installation wizard of the MSI downloaded above.
  3. Add references to the test project to the Typemock Isolator C# APIs and Typemock Isolator core DLL assemblies. These assemblies are installed to the GAC (Global Assembly Cache) by the installer and so appear in the .NET tab of the Add Reference dialog.

The following test makes use of Typemock Isolator allowing the GetTitle() method to use Sitecore.Data.Items.Item directly again without the need for an adapter.

[NUnit.Framework.Test, TypeMock.ArrangeActAssert.Isolated] 
public void GetTitle() 
{ 
  var item = TypeMock.ArrangeActAssert.Isolate.Fake.Instance<Item>(); 
  TypeMock.ArrangeActAssert.Isolate.WhenCalled(() => item["title"])
    .WillReturn("the title");

  var title = Web.ItemUtil.GetTitle(item); 
  Assert.AreEqual("the title", title); 
}

The above code first creates a mock that mimics the interface of Sitecore.Data.Items.Item. The mock is then configured to return a specific value when the title field is accessed. The mock is then passed to the original version of the GetTitle() method which accepts an instance of Sitecore.Data.Items.Item and the outcomes asserted.

The biggest benefit of using Typemock Isolator is that your project code doesn’t need to change to allow the tests to run as it did when using a mocking framework. There’s no need to use an adapter to wrap the Sitecore objects.

Conclusion

So there’s a few techniques for mocking with Sitecore objects. Now I’ve given you the gun, please be careful with it.

Comments

Great post I wrote a post about mocking Sitecore Item a while ago. But instead of using a mocking framework i created my own mock which derives from Sitecore.Data.Item. But I've also tried using the Typemock which i think i very powerfull. But I would be a lot easier to write test if Sitecore would use intefaces or abstract class's. Link to my post http://blog.istern.dk/2012/02/07/unit-testing-with-sitecore-item/
But all in all a good post.

Leave a comment

All fields are required.