ASP.NET MVC: Mock controller.Url.Action
URL-адреса в моих приложениях ASP.NET MVC генерируются из контроллера/действий. Таким образом, они называют
controller.Url.Action(action, controller)
Теперь, как мне сделать эту работу в модульных тестах?
Я успешно использую MVCContrib с
var controller = new TestControllerBuilder().CreateController<OrdersController>();
но все, что я пытаюсь сделать с ним, я получаю control.Url.Action(действие, контроллер) с ошибкой NullReferenceException, потому что Url == null.
Обновление: это не о том, как перехватить HttpContext. Я сделал это несколькими способами, используя MVCContrib, пример фальсификации Скотта Хансельмана, а также один из http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx. Это не помогает мне, потому что мне нужно знать значения WHAT для подделки... это ApplicationPath? Как мне настроить его? Нужно ли соответствовать вызываемому контроллеру/действию? То есть, как работает Url.Action и как его удовлетворить?
Кроме того, я знаю, что могу выполнять IUrlActionAbstraction и идти с ним... но я не уверен, что хочу это сделать. В конце концов, у меня есть MVCContrib/Mock полная мощность и почему мне нужна другая абстракция.
Ответы
Ответ 1
Вот как вы могли бы издеваться над UrlHelper с помощью MvcContrib TestControllerBuilder:
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
HomeController controller = CreateController<HomeController>();
controller.HttpContext.Response
.Stub(x => x.ApplyAppPathModifier("/Home/About"))
.Return("/Home/About");
controller.Url = new UrlHelper(
new RequestContext(
controller.HttpContext, new RouteData()
),
routes
);
var url = controller.Url.Action("About", "Home");
Assert.IsFalse(string.IsNullOrEmpty(url));
Ответ 2
Более чистый способ сделать это - просто использовать Moq (или любую другую структуру, которая вам нравится) для самого Mock UrlHelper
var controller = new OrdersController();
var Mock<UrlHelper> UrlHelperMock = new Mock<UrlHelper>();
controller.Url = UrlHelperMock.Object;
UrlHelperMock.Setup(x => x.Action("Action", "Controller", new {parem = "test"})).Returns("testUrl");
var url = controller.Url.Action("Action", "Controller", new {parem = "test"});
assert.areEqual("/Controller/Action/?parem=test",url);
чистый и простой.
Ответ 3
Подделка легко справляется:
var fakeUrlHelper = A.Fake<UrlHelper>();
controller.Url = fakeUrlHelper;
A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored))
.Returns("/Action/Controller");
Ответ 4
Если вы используете Moq
(а не MvcContrib
TestControllerBuilder
), вы можете издеваться над контекстом, похожим на ответ @DarianDimitrov:
var controller = new OrdersController();
var context = new Mock<System.Web.HttpContextBase>().Object;
controller.Url = new UrlHelper(
new RequestContext(context, new RouteData()),
new RouteCollection()
);
Это не устанавливает свойство controller.HttpContext
, но позволяет Url.Action
выполнять (и возвращать пустую строку - не требует насмешек).