在ASP.NET MVC中模拟Controller.Url.Action(字符串,字符串,对象,字符串)

时间:2022-11-30 21:22:25

I use NUnit and Moq libraries for unit testing. I need to mock overloaded Url.Action(string, string, object, string), because my controller's action uses it to get an absolute url of an Action.

我使用NUnit和Moq库进行单元测试。我需要模拟重载Url.Action(字符串,字符串,对象,字符串),因为我的控制器的动作使用它来获取Action的绝对URL。

My try for now (look at MockUrlAction test):

我现在尝试(看看MockUrlAction测试):

[TestFixture]
public class ControllerTests   
{
    [Test]
    public void MockUrlAction()
    {
        var controller = new TestController();

        controller.Url = new UrlHelper(new RequestContext(MvcMoqHelpers.FakeHttpContext(), new RouteData()), GetRouteCollection());

        // it works
        Assert.AreEqual("/PathToAction", controller.Url.Action("TestAction")); 

        // but it doesn't work
        Assert.AreEqual("http://example.com/PathToAction", controller.Url.Action("TestAction", null, null, "http")); 
    }

    private RouteCollection GetRouteCollection()
    {
        BundleTable.MapPathMethod = MapBundleItemPath;
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);

        var adminArea = new AdminAreaRegistration();
        var adminAreaRegistrationContext = new AreaRegistrationContext(adminArea.AreaName, routes);
        adminArea.RegisterArea(adminAreaRegistrationContext);

        return routes;
    }
}

public static class MvcMoqHelpers
{
    public static HttpContextBase FakeHttpContext()
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();

        request.Setup(r => r.AppRelativeCurrentExecutionFilePath).Returns("/");
        request.Setup(r => r.ApplicationPath).Returns("/");
        response.Setup(s => s.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);

        context.Setup(ctx => ctx.Request).Returns(request.Object);
        context.Setup(ctx => ctx.Response).Returns(response.Object);
        context.Setup(ctx => ctx.Session).Returns(session.Object);
        context.Setup(ctx => ctx.Server).Returns(server.Object);

        return context.Object;
    }
}

And at the line

并在线

Assert.AreEqual("http://example.com/PathToAction", controller.Url.Action("TestAction", null, null, "http"));

I get an exception

我得到一个例外

System.NullReferenceException : Object reference not set to an instance of an object.
at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)
at System.Web.Mvc.UrlHelper.Action(String actionName, String controllerName, Object routeValues, String protocol)

It's strange for me that controller.Url.Action("TestAction") works fine, but controller.Url.Action("TestAction", null, null, "http") does not.

对我来说很奇怪,controller.Url.Action(“TestAction”)工作正常,但是controller.Url.Action(“TestAction”,null,null,“http”)却没有。

P.S. MvcMoqHelpers.FakeHttpContext() is from here, maybe it will help to answer the question.

附: MvcMoqHelpers.FakeHttpContext()来自这里,也许它将有助于回答这个问题。

So the question is: how can I get Url.Action(string, string, object, string) mocked?

所以问题是:我怎样才能得到Url.Action(字符串,字符串,对象,字符串)?

Thanks.

谢谢。

1 个解决方案

#1


10  

You have to set Request.Url, and you have that piece of code in tutorial which you provided:

你必须设置Request.Url,你在教程中提供了那段代码:

public static HttpContextBase FakeHttpContext(string url)
{
    HttpContextBase context = FakeHttpContext();
    context.Request.SetupRequestUrl(url);
    return context;
}

Reason is - in your Url.Action overload you do not provide hostname and protocol, so MVC tries to extract those values from Request.Url

原因是 - 在您的Url.Action重载中您没有提供主机名和协议,因此MVC尝试从Request.Url中提取这些值

if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
{
    Uri requestUrl = requestContext.HttpContext.Request.Url;
    protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
    hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host;

#1


10  

You have to set Request.Url, and you have that piece of code in tutorial which you provided:

你必须设置Request.Url,你在教程中提供了那段代码:

public static HttpContextBase FakeHttpContext(string url)
{
    HttpContextBase context = FakeHttpContext();
    context.Request.SetupRequestUrl(url);
    return context;
}

Reason is - in your Url.Action overload you do not provide hostname and protocol, so MVC tries to extract those values from Request.Url

原因是 - 在您的Url.Action重载中您没有提供主机名和协议,因此MVC尝试从Request.Url中提取这些值

if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
{
    Uri requestUrl = requestContext.HttpContext.Request.Url;
    protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
    hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host;