How to unit test a MVC HTML Helper that calls Action

17 Nov 2013

If you have a need to unit test a helper method which does a call to Action then you will hit an issue due to how HtmlHelper is not mockable and the call to Action will end up going through many layers and actually calling an action.

The below uses a simple property injection method to allow mocking the Action call so the rest of the helper functionality can be tested.

Helper class

Makes use of a static constructor and a public property holding the singleton of an invoker class that wraps the Action call.

    public static class SomeHtmlHelperClass
        static SomeHtmlHelperClass()
            ActionInvoker = new HtmlHelperActionInvoker();

        public static IHtmlHelperActionInvoker ActionInvoker { get; set; }

        public static MvcHtmlString RenderCMSObject(this HtmlHelper helper, CMSObject cmsObject)
            var actionName = string.IsNullOrEmpty(cmsObject.ActionName)
                ? "Index"
                : cmsObject.ActionName;

            var controllerName = string.IsNullOrEmpty(cmsObject.ControllerName)
                ? "Default"
                : cmsObject.ControllerName;

            return ActionInvoker.Action(helper, actionName, controllerName, cmsObject);

Invoker interface and class

Simple Interface and class that calls the Action method of helper, the concrete is very basic so it doesn't need testing.

    public interface IHtmlHelperActionInvoker
        MvcHtmlString Action(HtmlHelper helper, string action, string controller, CMSObject model);

    public class HtmlHelperActionInvoker : IHtmlHelperActionInvoker
        public MvcHtmlString Action(HtmlHelper helper, string action, string controller, CMSObject model)
            return helper.Action(action, controller, model);

Unit Test

Mocks the invoker using Moq to return a string, which is then asserted at the end. The mocked class is injected into the helper via property injection before the helper is executed.

    public class HelperTests
        public void GivenACmsObjectWithCompletedActionAndController_WhenRenderCMSObject_ThenExpectedActionOutcomeforActionAndControllerIsGiven()
            const string actionName = "foo";
            const string controllerName = "bar";
            const string expectedOutcome = "<h1>Bruce</h1>";

            // Arrange
            var cmsObject = new CMSObject { ActionName = actionName, ControllerName = controllerName };

            var mockInvoker = new Mock();
            mockInvoker.Setup(x => x.Action(null, actionName, controllerName, cmsObject)).Returns(MvcHtmlString.Create(expectedOutcome));
            SomeHtmlHelperClass.ActionInvoker = mockInvoker.Object;

            // Act
            var result = SomeHtmlHelperClass.RenderCMSObject(null, cmsObject);

            // Verify
            Assert.That(result.ToString(), Is.EqualTo(expectedOutcome));
    }   mvc   testing   nunit   moq  
Posted by makit
Last revised 17 Nov 2013 02:51 PM

makit / Martyn Kilbryde

Professional software developer, ponderer and eccentric.




Stack Overflow