I am writing a unit test for HtmlHelper
extension method, but it's a bit tricky because it calls UrlHelper
inside the method rather than using dependency injection. That means I can't just mock UrlHelper
.
So, in my test, I created a HtmlHelper
object and mocked all necessary properties. I did my best to set up HtmlHelper.ViewContext.RequestContext
, since that's what UrlHelper
relies on when it's constructed. But when I debugged it, UrlHelper.Action
returned null
.
I’d appreciate any insights on what could be causing this issue!
Original method:
public static bool IsActive(this HtmlHelper helper, string actionName, string controllerName, string areaName)
{
string currentUrl = helper.ViewContext.HttpContext.Request.RawUrl;
UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
string url = urlHelper.Action(actionName, controllerName, new { area = areaName });
return currentUrl.Contains(url);
}
Here's my attempt:
[Fact]
public void IsActive_WhenUrlIsCurrentUrl_ReturnsTrue()
{
// Arrange
var dictionary = new { action = "Index", controller = "Home", area = "Admin" };
var viewDataDictionary = new ViewDataDictionary(dictionary);
var htmlHelper = MvcHelper.GetHtmlHelperWithPath(viewDataDictionary, "/Home/Index/Admin");
// Act
var result = htmlHelper.IsActive("Index", "Home", "Admin");
// Assert
Assert.True(result);
}
public static class MvcHelper
{
public const string AppPathModifier = "/$(SESSION)";
public static HtmlHelper GetHtmlHelperWithPath(ViewDataDictionary viewData, string appPath)
{
ViewContext viewContext = GetViewContextWithPath(appPath, viewData);
Mock<IViewDataContainer> mockContainer = new Mock<IViewDataContainer>();
mockContainer.Setup(c => c.ViewData).Returns(viewData);
IViewDataContainer container = mockContainer.Object;
return new HtmlHelper(viewContext, container);
}
public static ViewContext GetViewContextWithPath(string appPath, ViewDataDictionary viewData)
{
HttpContextBase httpContext = GetHttpContext(appPath, "/request", "GET", Uri.UriSchemeHttp.ToString());
Mock<ViewContext> mockViewContext = new Mock<ViewContext>() { DefaultValue = DefaultValue.Mock };
RouteData rd = new RouteData();
rd.Values.Add("controller", "Home");
rd.Values.Add("action", "Index");
rd.Values.Add("area", "Admin");
mockViewContext.Object.RequestContext = new RequestContext(httpContext, rd);
mockViewContext.Setup(c => c.HttpContext).Returns(httpContext);
mockViewContext.Setup(c => c.ViewData).Returns(viewData);
mockViewContext.Setup(c => c.Writer).Returns(new StringWriter());
return mockViewContext.Object;
}
public static HttpContextBase GetHttpContext(string appPath, string requestPath, string httpMethod, string protocol)
{
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Setup(o => o.Request.ApplicationPath).Returns(appPath);
mockHttpContext.Setup(o => o.Request.RawUrl).Returns(appPath);
mockHttpContext.Setup(o => o.Request.AppRelativeCurrentExecutionFilePath).Returns(requestPath);
Uri uri = new Uri(protocol + "://localhost");
mockHttpContext.Setup(o => o.Request.Url).Returns(uri);
mockHttpContext.Setup(o => o.Request.PathInfo).Returns(String.Empty);
mockHttpContext.Setup(o => o.Request.HttpMethod).Returns(httpMethod);
mockHttpContext.Setup(o => o.Session).Returns((HttpSessionStateBase)null);
mockHttpContext.Setup(o => o.Response.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(r => AppPathModifier + r);
mockHttpContext.Setup(o => o.Items).Returns(new Hashtable());
return mockHttpContext.Object;
}
}
I am writing a unit test for HtmlHelper
extension method, but it's a bit tricky because it calls UrlHelper
inside the method rather than using dependency injection. That means I can't just mock UrlHelper
.
So, in my test, I created a HtmlHelper
object and mocked all necessary properties. I did my best to set up HtmlHelper.ViewContext.RequestContext
, since that's what UrlHelper
relies on when it's constructed. But when I debugged it, UrlHelper.Action
returned null
.
I’d appreciate any insights on what could be causing this issue!
Original method:
public static bool IsActive(this HtmlHelper helper, string actionName, string controllerName, string areaName)
{
string currentUrl = helper.ViewContext.HttpContext.Request.RawUrl;
UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
string url = urlHelper.Action(actionName, controllerName, new { area = areaName });
return currentUrl.Contains(url);
}
Here's my attempt:
[Fact]
public void IsActive_WhenUrlIsCurrentUrl_ReturnsTrue()
{
// Arrange
var dictionary = new { action = "Index", controller = "Home", area = "Admin" };
var viewDataDictionary = new ViewDataDictionary(dictionary);
var htmlHelper = MvcHelper.GetHtmlHelperWithPath(viewDataDictionary, "/Home/Index/Admin");
// Act
var result = htmlHelper.IsActive("Index", "Home", "Admin");
// Assert
Assert.True(result);
}
public static class MvcHelper
{
public const string AppPathModifier = "/$(SESSION)";
public static HtmlHelper GetHtmlHelperWithPath(ViewDataDictionary viewData, string appPath)
{
ViewContext viewContext = GetViewContextWithPath(appPath, viewData);
Mock<IViewDataContainer> mockContainer = new Mock<IViewDataContainer>();
mockContainer.Setup(c => c.ViewData).Returns(viewData);
IViewDataContainer container = mockContainer.Object;
return new HtmlHelper(viewContext, container);
}
public static ViewContext GetViewContextWithPath(string appPath, ViewDataDictionary viewData)
{
HttpContextBase httpContext = GetHttpContext(appPath, "/request", "GET", Uri.UriSchemeHttp.ToString());
Mock<ViewContext> mockViewContext = new Mock<ViewContext>() { DefaultValue = DefaultValue.Mock };
RouteData rd = new RouteData();
rd.Values.Add("controller", "Home");
rd.Values.Add("action", "Index");
rd.Values.Add("area", "Admin");
mockViewContext.Object.RequestContext = new RequestContext(httpContext, rd);
mockViewContext.Setup(c => c.HttpContext).Returns(httpContext);
mockViewContext.Setup(c => c.ViewData).Returns(viewData);
mockViewContext.Setup(c => c.Writer).Returns(new StringWriter());
return mockViewContext.Object;
}
public static HttpContextBase GetHttpContext(string appPath, string requestPath, string httpMethod, string protocol)
{
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Setup(o => o.Request.ApplicationPath).Returns(appPath);
mockHttpContext.Setup(o => o.Request.RawUrl).Returns(appPath);
mockHttpContext.Setup(o => o.Request.AppRelativeCurrentExecutionFilePath).Returns(requestPath);
Uri uri = new Uri(protocol + "://localhost");
mockHttpContext.Setup(o => o.Request.Url).Returns(uri);
mockHttpContext.Setup(o => o.Request.PathInfo).Returns(String.Empty);
mockHttpContext.Setup(o => o.Request.HttpMethod).Returns(httpMethod);
mockHttpContext.Setup(o => o.Session).Returns((HttpSessionStateBase)null);
mockHttpContext.Setup(o => o.Response.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(r => AppPathModifier + r);
mockHttpContext.Setup(o => o.Items).Returns(new Hashtable());
return mockHttpContext.Object;
}
}
Share
Improve this question
edited yesterday
Brook
asked Mar 20 at 16:03
BrookBrook
13 bronze badges
0
1 Answer
Reset to default 0using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
using NUnit.Framework;
[TestFixture]
public class UrlHelperTests
{
private UrlHelper GetUrlHelper()
{
// Mock HttpContextBase
var httpContextMock = new Mock<HttpContextBase>();
var requestMock = new Mock<HttpRequestBase>();
var responseMock = new Mock<HttpResponseBase>();
httpContextMock.Setup(c => c.Request).Returns(requestMock.Object);
httpContextMock.Setup(c => c.Response).Returns(responseMock.Object);
// Set up Request URL
requestMock.Setup(r => r.ApplicationPath).Returns("/");
requestMock.Setup(r => r.Url).Returns(new System.Uri("http://localhost"));
requestMock.Setup(r => r.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
// Set up Response
responseMock.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);
// Create RouteData
var routeData = new RouteData();
routeData.Values["controller"] = "Home";
routeData.Values["action"] = "Index";
// Create RequestContext
var requestContext = new RequestContext(httpContextMock.Object, routeData);
// Create UrlHelper
return new UrlHelper(requestContext, new RouteCollection());
}
[Test]
public void UrlHelper_Action_Generates_Correct_Url()
{
var urlHelper = GetUrlHelper();
string result = urlHelper.Action("Index", "Home");
Assert.AreEqual("/Home/Index", result);
}
}