Unit testing in EPiServer 7

This post shows a basic example of how to mock EPiServer dependencies for unit tests.

  • Ted Nyberg
  • 15 October 2013
  • 0

A (previously) difficult-to-test method in EPiServer

Consider the following method. It takes a page as a parameter and looks for a property on that page. If the property is set, it is simply returned. If it isn’t set, we return the value of a property from another page:

public static string GetAuthor(MyPageType page)
{
    if (!string.IsNullOrWhiteSpace(page.Author))
    {
        return page.Author;
    }

    // Fallback to company name set on start page
    ServiceLocator.Current.GetInstance<IContentRepository>().Get<StartPage>(ContentReference.StartPage).CompanyName;
}

All of a sudden we have a dependency to EPiServer which (in the old days) would make this method quite difficult to unit test. So difficult in fact that we pretty much never did it… Luckily that has changed dramatically with EPiServer 7.

Create a new unit test class

I use MSTest quite a bit. It’s already included in most versions of Visual Studio, and it does a good enough job for me in many cases.

First, we add a new Basic Unit Test to our project:

image

A unit test class is like any other class, except that it has some extra test attributes:

image

Create a test method

Next we rename TestMethod1 into something more descriptive and do some very basic mocking to test our GetAuthor() method. I like the Arrange Act Assert pattern, which is basically just a way of structuring your unit tests:

[TestMethod]
public void TestCompanyNameIsReturnedIfAuthorIsNotSet()
{
    // Arrange, create a mock page with an empty Author property
    var page = new MyPageType { Author = null };

    var startPage = ServiceLocator.Current.GetInstance<IContentRepository>().Get<StartPage>(ContentReference.StartPage);

    // Act, invoke the method we're testing
    var author = PageMetaData.GetAuthor(page);

    // Assert, we should have gotten the company name from the start page as a fallback value
    Assert.AreEqual(author, startPage.CompanyName);
}

Now we see that both our test and the method we’re testing have dependencies to EPiServer, more specifically to IContentRepository.

If we try to execute our unit test now we’ll see an error like “Activation error occurred while trying to get instance of type IContentRepository” (which makes sense since EPiServer isn’t running):

image

Add a mocking framework to your test project

Mocking is the process of creating fake objects. Mocking frameworks commonly allow you to get concrete (but fake) implementations of interfaces, and then specify how those fake objects should behave (for example which values should be returned by their properties and methods).

One of my favorite mocking frameworks is Moq. To enable it for your tests, simply add the Moq NuGet package:

image

Mock IContentRepository for our unit tests

MSTest allows us to execute code to initialize tests, sort of an over-arching arrange for all test methods:

image

For our unit test we need a mock IContentRepository which can return a start page so that a method like the following method can execute in a unit test:

ServiceLocator.Current.GetInstance<IContentRepository>().Get<StartPage>(ContentReference.StartPage).CompanyName;

So, we add an initialization method decorated with the TestInitialize attribute to our test class. In this method we mock an IContentRepository and an IServiceLocator. Finally we tell EPiServer to use our fake service locator when resolving dependencies:

[TestInitialize]
public void MockEPiServerDependencies()
{
    // Create a mock repository
    var mockRepository = new Mock<IContentRepository>();

    // Setup the repository to return a start page with a preset property value
    mockRepository.Setup(r => r.Get<StartPage>(ContentReference.StartPage)).Returns(new StartPage { CompanyName = "My company name" });

    // Create a mock service locator
    var mockLocator = new Mock<IServiceLocator>();

    // Setup the service locator to return our mock repository when an IContentRepository is requested
    mockLocator.Setup(l => l.GetInstance<IContentRepository>()).Returns(mockRepository.Object);

    // Make use of our mock objects throughout EPiServer
    ServiceLocator.SetLocator(mockLocator.Object);
}

Now we can re-run our original unit test and - voilá:

image

Notice how we indeed got a start page with its CompanyName property! Now we can re-run our original unit test and see that it passes successfully:

image