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.

    [TestFixture]
    public class HelperTests
    {
        [Test]
        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));
        }
    }
asp.net   mvc   testing   nunit   moq  
Posted by makit
Last revised 17 Nov 2013 02:51 PM

makit / Martyn Kilbryde

Professional software developer, ponderer and eccentric.

flickr

Github

LinkedIn

Stack Overflow

Twitter