Unit-testing your DD4T code with Mock objects

Unit testing your code is a great way to make sure your code works as expected, now, and in the future, after loads of changes to your project.

Writing tests can be pretty simple, if you have functionality that only relies on logic, but what if your code relies on ‘external’ data. How would you test that?

As most of the DD4T functionality eventually makes calls to the SDL Tridion broker database, using componentproviders, linkproviders,… it becomes more difficult to write unit tests.

An example : let’s say you have a function that tries to get a component based on the passed tcm uri, checks if the schema id corresponds to a value in your configuration settings, and if this is true, performs some more logic (which we want to test).

A naive way of doing this is to public a component of that particular schema to your broker, make sure your unit-test framework can actually access the broker, and then write a test with your published component id.

While that might work fine for now, and maybe for the next couple of days, but how will you know it will keep working in a few years ? What if someone unpublishes, or even deletes your test component. Your tests will then fail, you’ll need to figure out why, and you lose a lot of time.

The answer lies in mock objects. Using this technique, you can write “mock” statements for code that your functions rely on (such as broker queries) but that you don’t want to test (you want to test your functionality, but you don’t want to test broker querying, as you know that this should behave as expected).

In my next code example, i’m using the library called Moq.

So, we have a function that calls the trygetcomponent function of the DD4T ComponentProvider. The  actual logic behind the function is not really relevant right now, so i omitted it

public class YourClass{
 public YourClass(IComponentFactory componentFactory){
//set your classes component factory here
}
public string ResolveLink(string componentUri)
{
IComponent component = null;
if (this.componentFactory.TryGetComponent(componentUri, out component))
{
TcmUri schemaId = new TcmUri(component.Schema.Id);
if (schemaId.ItemId == int.Parse(this.configurationManager.AppSettings["ArticleSchemaId"]))
{
//some logic here
}
else
{
//some other logic here
}
}
}
}

Now, you can write a unit test for this function like this

[TestMethod]
public void Test_Using_Moq()
{
Mock<IComponentFactory> myComponentFactoryMock = new Mock<IComponentFactory>();

IComponentFactory componentFactory = new ComponentFactory();
string TestDD4TXML = @"<Component><Id>tcm:17-1736</Id><Title>some test component</Title><Publication><Id>tcm:0-17-1</Id><Title>My Publication</Title>... rest omitted for brevity...</Component>";

var component = componentFactory.GetIComponentObject(TestDD4TXML);//this piece of code transforms the xml in an actual IComponent object

myComponentFactoryMock.Setup(c => c.TryGetComponent(It.Is<string>(s=>s == "tcm:17-1736"), out component, It.IsAny<string>())).Returns(true);
YourClass a = new YourClass(myComponentFactoryMock.Object);
var returnvalue = a.ResolveLink("tcm:17-1736");
Assert.AreEqual(returnvalue, "expected value");
}

A small breakdown of what this test function does

First, it creates a new Mock object for your IComponentFactory.
Then, it creates an IComponent object with some DD4T XML of a Tridion Component you wish to test with (you can obtain this by previewing your published component in tridion.
Now comes the complex bit. You define that your ComponentFacotry mock object returns a specific value if the function “TryGetComponent” is being called. In our case, it will set the out parameter to your component object, and return true.
This way, the componentfactory will not really call the broker database, but will return you a correct tridion object, no matter if it’s actually published to the broker or not

Then, I instantiate an object of the class I wish to test, and I pass the mock object to it. This way, my class won’t use the real componentfactory, but my mocked component factory).

Then, i can call my function, so I can test my functionality. I know that the component i’m testing it with won’t be fetched from the broker, but it will use the component i initiated before.

This is just a small example of what you can do that I wanted to share. I’ve also just started to use this framework.
If you have anything you wish to add, or if you are using some similar ways to test your code, feel free to comment.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>