Mocking Controller.Url.Action (строка, строка, объект, строка) в ASP.NET MVC

Я использую NUnit и Moq библиотеки для модульного тестирования. Мне нужно издеваться над перегруженным Url.Action (string , строка, объект, строка), потому что действие моего контроллера использует его, чтобы получить абсолютный URL-адрес действия .

Моя попытка на данный момент (посмотрите тест 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;
    }
}

И на линии

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

Я получаю исключение

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)

Для меня странно, что controller.Url.Action("TestAction") работает нормально, а controller.Url.Action("TestAction", null, null, "http") - нет.

P.S. MvcMoqHelpers.FakeHttpContext () взят из здесь, возможно, это поможет ответить на вопрос.

Итак, вопрос: как я могу смоделировать Url.Action (string, string, object, string)?

Спасибо.


person kasitan    schedule 06.03.2013    source источник
comment
А как насчет URL-адреса в context.Request.SetupRequestUrl (url)?   -  person Nenad    schedule 07.03.2013
comment
Возможный дубликат ASP.NET MVC: Mock controller.Url.Action   -  person Michael Freidgeim    schedule 03.07.2017


Ответы (1)


Вы должны установить Request.Url, и у вас есть этот фрагмент кода в учебнике, который вы предоставили:

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

Причина в том, что в вашей перегрузке 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;
person Nenad    schedule 06.03.2013
comment
Кажется, ты прав. Я изменил метод public static void SetupRequestUrl(this HttpRequestBase request, string url) из этого руководства, добавив строку mock.Setup(req => req.Url).Returns(new Uri(new Uri("http://localhost/"), url));, и теперь он, кажется, работает, если я вызываю перегруженный FakeHttpContext(string url). Я не уверен, что это самый простой способ исправить, но все равно принимаю ваш ответ. Спасибо. - person kasitan; 07.03.2013