最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to set up RequestContext for UrlHelper in ASP.NET unit tests - Stack Overflow

programmeradmin2浏览0评论

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
Add a comment  | 

1 Answer 1

Reset to default 0
using 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);
    }
}
发布评论

评论列表(0)

  1. 暂无评论