Software Engineering, Architecture and AWS Serverless Technology from makit
November 17, 2013

How to unit test a MVC HTML Helper that calls Action

Posted on November 17, 2013  •  2 minutes  • 311 words
Table of contents

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<IHtmlHelperActionInvoker>();
		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));
Follow me

If you are interested in Coding, AWS, Serverless or ML