Unit Test Umbraco Controllers

How to Inject Umbraco Dependencies into an Umbraco Controllers in a Test Project

Umbraco unit testing TDD Tuesday, May 20, 2014

First of all, you should know that there are two types of special controllers in Umbraco: RenderMvcController and SurfaceController.

The former is used to hi-jack routes (basically, whenever the browser asks for a certain node URL and its document type matches the name of a RenderMvcController, the Index action is the controller is executed and you may return a view model that you can use in the view).

The latter is used to handle post requests, render child actions inside templates and those sorts of things.

Before proceeding, you should understand the above. Consult the Umbraco documentation about RenderMvcControllers and SurfaceControllers.

Also, before proceeding, make sure you have your solution prepared to start create stubs of Umbraco depependencies.

Unit Testing an Umbraco Controller

Let's say we have a SiteSurfaceController (a RenderMvcController would be tested the same way) that we use to render child actions like Header and Footer. The following is a part of the implementation of SiteSurfaceController (the complete solution source code is attached).

public class SiteSurfaceController : SurfaceController
    public SiteSurfaceController(
        ISiteService siteService, ICategoryService categoryService, IPostService postService,
        IContactService contactService, IAuthorService authorService, ILinkService linkService,
        UmbracoContext umbracoContext)
        : base(umbracoContext)
        // Sets private fields here.

    public ActionResult Header()
        var model = new HeaderViewModel()
                Categories = new List()

        foreach (var category in this.categoryService.GetRootCategories())
            var categoryViewModel = new CategoryViewModel();
            categoryViewModel.CategoryData = category;

        return PartialView("Header", model);

I used TDD software development process to create the above code but I decided to go backwards for the purpose of demonstrating how to unit test a controller.

The following is the a part of the test class that contains a test to verify that the action result returned is a PartialView and the view name is Header.

Care to notice that the unit test below has 2 line spaces separating 3 parts of the unit test: prepare, execute and assert.

In the preparation part of the unit test, we have an object mockedServices that just contains mocks for each possible service later injected in the controller. I created the MocksFactory.CreateMockedBusinessServices() helper method so I wouldn't have to write new Mock<IWhateverService>() for every new service mock I need as it would make the unit tests more complex and, therefore, less maintanable. Then, the CreateSiteController method just instantiates a new SiteSurfaceController.

The Header action method is executed and it's for assertions.

A critical part here is to make sure that you pass the stubbed instance of UmbracoContext to the SurfaceController constructor (see in bold).

public class SiteControllerTests : BaseRoutingTest
    private UmbracoContext umbracoContext;

    public void SetUp()
        this.umbracoContext = GetRoutingContext("/").UmbracoContext;

    public void Header_Always_ReturnsHeaderPartialView()
        var mockedServices = MocksFactory.CreateMockedBusinessServices();
        var siteController = this.CreateSiteController(mockedServices);

        var result = siteController.Header();

        // If the result is not null, of type PartialViewResult and, obviously, the view name is
        // "Header", the test passes.
        Assert.AreEqual(((PartialViewResult)result).ViewName, "Header");

    private SiteSurfaceController CreateSiteController(MockedBusinessServicesData mockedServices)
        return new SiteSurfaceController(
                        this.umbracoContext /* UmbracoContext stub */);

The next post tell you how to unit test a SurfaceController action method on a POST submission. It is a bit more complex but, luckily, all you have to do is copy/paste some code to your test project so you can things running.