Episerver 7 : Unit Testing Using Mocks – Unit Testing Part 2

This is the second part of my unit testing series.  In Unit Testing Part 1 I discussed simple ways that you can organise your project so all the Episerver API dependencies are hidden away in a single file to help improve your sites testability. As of yet we haven’t gone into the details of why this helps us so much.

In this article we’ll start to write some of the unit tests and, hopefully, it should be clear how using Mocks to swap out all of Episerver’s dependencies allows us to create testable code.  Before we start I’ll be using three packages available from Nuget:

I won’t go into the in’s and out’s of the frameworks, instead I’ll mainly be showing some code examples of how to write Mock’s for Episerver

Injected – Testing A Controller Using Epi Dependencies

If you look in the Alloy site in the controllers folder, you will soon come across the Injected property.  Interfaces wrapped in an Injected are constructed via new the new service locator using the global service locator object.  This is really cool and useful, however, if you try and do the following test you will get an ActivationException

public class Controller<T> : PageController<pageType>
{
internal Injected<IEpiserverDependencies> EpiserverDependenciesService;
protected IEpiserverDependencies EpiserverDependencies
{
get { return EpiserverDependenciesService.Service; }
}
var contentPageController = new Controller();
}

So, how do we test a view model if it uses Injected for the EpiDependencies ?  This is where we use Mock to mimic the bit that injects the IEpiDependencies into our controller and gets rid of that exception.

var serviceLocator = new Mock<IServiceLocator>();
var contentRepositoryFactory = new Mock<IContentRepositoryFactory>();
var linkResolverFactory = new Mock<ILinkResolverFactory>();
var epiServerDependencies = new EpiserverDependencies(
contentRepositoryFactory.Object,
linkResolverFactory.Object);
serviceLocator.Setup(x => x.GetInstance<IEpiserverDependencies>()).Returns(epiServerDependencies);
ServiceLocator.SetLocator(serviceLocator.Object);

If you now create a new Controller, Mock will inject mimic interfaces and classes so our code will load!  This is a big step forward as now you can write unit tests to test the functionality you want.  Below shows a fully working test

[TestFixtureSetUp]
public void Setup()
{
var serviceLocator = new Mock<IServiceLocator>();
var contentRepositoryFactory = new Mock<IContentRepositoryFactory>();
var linkResolverFactory = new Mock<ILinkResolverFactory>();
var epiServerDependencies = new EpiserverDependencies(
contentRepositoryFactory.Object,
linkResolverFactory.Object);
serviceLocator.Setup(x => x.GetInstance<IEpiserverDependencies>()).Returns(epiServerDependencies);
ServiceLocator.SetLocator(serviceLocator.Object);
}
[Test]
public void Will_Controller_Load_With_Dependencies()
{
var mockContentPage = new Mock<ContentPage>();
var contentPageController = new ContentPageController();
var result = contentPageController.Index(mockContentPage.Object);
result.Should().NotBeNull();
}

Testing Pages and Content Areas

So, now we have covered how to Mock up a controller, the next bit we can move onto is how to Mock a page up.. specifically a page with a Content Area and items within that area.  This one involves a bit more code, I’m still using the [TestFixtureSetUp] method above. In this test we need to create a content area object, populate it with a content area item object.

[Test]
public void Adding_To_Content_Area()
{
var content = new Mock<IContent>();
content.Setup(x => x.ContentLink).Returns(new ContentReference(1));
var contentAreaItemList = new List<ContentAreaItem>
{
new ContentAreaItem { ContentLink = content.Object.ContentLink }
};
var contentArea = new Mock<ContentArea>();
contentArea.Setup(x => x.Items).Returns(contentAreaItemList);
var mockContentPage = new Mock<ContentPage>();
mockContentPage.Setup(u => u.MainContentArea).Returns(contentArea.Object);
var controller = new ContentPageController();
var contentAreaResult = controller.ReturnContentArea(mockContentPage.Object);
contentAreaResult.ContentLink.Should().Be(new ContentReference(1));
}

We now have a test to ensue that the iContent has been added.  This test in itself is pretty boring but it does give you the framework to start fully testing any part of your page types and content areas you might need.

The code for the whole of this series can be found on my github.. here enjoy :)

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

6 replies
  1. Andy
    Andy says:

    Thanks for posting the examples above – been good to get me started. Having trouble extending your content area example though, as I want to have instances of specific blocks in my content area that I’m preparing to test against, rather then simply mocked IContent. In other words, instead of…

    var content = new Mock();

    .. I want to do

    var content = new Mock();

    But then I don’t have an IContent to populate the ContentArea with.

    Could I ask if you’ve been able to extend the method you’ve outlined this way please?

    Reply
  2. Andy
    Andy says:

    Afraid some code got eaten in the above, but hopefully you get the idea. Basically I’m looking to pass in instances of specific blocks to the content area rather than just generic IContent instances. Thanks.

    Reply
    • jon
      jon says:

      Hi, Yes you can manually add block directly or by mocking them into a content area, something like the below:

      var block = new Block();
      var contentArea new ContentArea
      {
      Items =
      {
      new ContentAreaItem { ContentLink = block.ContentLink }
      }
      },

      Reply
  3. Andy
    Andy says:

    Thanks for replying Jon. I tried something like that, but blocks (inheriting from BlockData) don’t have a ContentLink property:
    http://world.episerver.com/Forum/Developer-forum/EPiServer-7-CMS/Thread-Container/2013/7/Block-ContentReference-ID/

    As per that article, I’ve also tried casting the block to IContent, which compiles and then exposes the ContentLink property. However that leads to an error “Unable to cast object of type ‘MyProject.Models.Blocks.MyBlock’ to type ‘EPiServer.Core.IContent’ when the test is run.

    Reply
    • jon
      jon says:

      The convert to IContent is a pain. One way I could think of to get around it would be something like, on all my projects I always have a base block type that all blocks inherit from. IN the base block have a ContentLink method/property. In the property do the usual (IContent)this.ContentLink. In your code use that property eberywhere, in your test mock the block and create a Moq setup that returns the content link you want to. Tat way your convert is hidden in the block and you don’t have to worry aobut the convert issue in your test

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

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