2009-03-23 3 views
164

Один из моих действий с контроллерами, вызываемый в запросе Ajax, возвращает URL-адрес на стороне клиента, чтобы он мог перенаправлять. Я использую Url.RouteUrl(..), и во время моих модульных тестов это не срабатывает, поскольку параметр Controller.Url не заполняется заранее.ASP.NET MVC: Контроллеры модулей тестирования, использующие UrlHelper

Я пробовал много вещей, среди других, пытающихся окурок UrlHelper (который не удалось), создавая UrlHelper вручную с RequestContext который имеет погасил HttpContextBase (который не удалось на RouteCollection.GetUrlWithApplicationPath вызова).

Я искал Google, но практически ничего не нашел по этому вопросу. Я делаю что-то невероятно глупо, используя Url.RouteUrl в моем контролере? Есть ли более простой способ?

Чтобы сделать это еще хуже, я хотел бы проверить тестовый результат в моем модульном тесте - на самом деле мне интересно только, чтобы он перенаправлялся на правильный маршрут, но поскольку я возвращаю URL вместо маршрута, я хотел бы управлять URL-адресом, который разрешен (например, с помощью заштрихованного RouteCollection), но я с удовольствием пройду свой тест.

ответ

196

Вот один из моих тестов (XUnit + MOq) как раз для подобного случая (с использованием Url.RouteUrl в контроллере)

Надеется, что это помогает:

var routes = new RouteCollection(); 
MvcApplication.RegisterRoutes(routes); 

var request = new Mock<HttpRequestBase>(MockBehavior.Strict); 
request.SetupGet(x => x.ApplicationPath).Returns("/"); 
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute)); 
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection()); 

var response = new Mock<HttpResponseBase>(MockBehavior.Strict); 
response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1"); 

var context = new Mock<HttpContextBase>(MockBehavior.Strict); 
context.SetupGet(x => x.Request).Returns(request.Object); 
context.SetupGet(x => x.Response).Returns(response.Object); 

var controller = new LinkbackController(dbF.Object); 
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); 
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes); 
+2

В настоящее время я пошел с решением, где я отвлек звонки на UrlHelper, чтобы я мог их перехватить. Однако, спасибо за ваш фрагмент, это избавит меня от времени, чтобы выяснить, как правильно издеваться над Request/Response/ControllerContext. – efdee

+0

Спасибо за ответ @ eu-ge-ne, это тоже помогло мне. Я включил еще несколько настроек moq, чтобы использовать параметр formcollection, используемый UpdateModel – woopstash

+16

+1 отлично. Хотя совет: я использую это как MockHelper и изменяю ответ. Для приложения ApplyAppPathModifier: response.Setup (x => x.ApplyAppPathModifier (Moq.It.IsAny ())).Возвращает ((String url) => url); Это уродливо, но я возвращаю сериализованный объект в кодировке url, а не hardcoding возвращаемое значение. – eduncan911

12

Это сообщению может быть полезно, если вы хотите для издевательства класса HttpContextBase.

http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

+0

Прохладный, это помогло мне, хотя мне пришлось добавить дополнительный код к методу FakeHttpContext, чтобы остановить вспомогательный вызов: context.Setup (ctx => ctx.Request.ApplicationPath). Возвраты ("/ AntiBlowup "); Я также реорганизовал код, чтобы он использовал новый синтаксис Setup(). Спасибо. – RichardOD

2

Строительство ответ на @ ес-ге-пе, который помог мне многое:

Я имел ActionResult что сделал редирект, а также был UpdateModel вызов с параметром FormCollection , Для UpdateModel() для работы я должен был добавить это к моему Передразнивало HttpRequestBase:

FormCollection collection = new FormCollection(); 
collection["KeyName"] = "KeyValue"; 

request.Setup(x => x.Form).Returns(collection); 
request.Setup(x => x.QueryString).Returns(new NameValueCollection()); 

Чтобы проверить, перенаправляется URL был правильно, вы можете сделать следующее:

RedirectResult result = controller.ActionName(modelToSubmit, collection) as RedirectResult; 
Assert.AreEqual("/Expected/URL", result.Url); 
33

Модифицированная реализация от eu-ge-ne. Это возвращает сгенерированную ссылку на основе маршрутов, определенных в приложении. Пример eu-ge-ne всегда возвращал фиксированный ответ. Приведенный ниже подход позволит вам проверить, что правильная информация о действии/контроллере и маршруте передается в UrlHelper - это то, что вы хотите, если вы тестируете вызов UrlHelper.

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>(); 

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); 

request.SetupGet(x => x.ApplicationPath).Returns("/"); 
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute)); 
request.SetupGet(x => x.ServerVariables).Returns(new NameValueCollection()); 

response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x); 

context.SetupGet(x => x.Request).Returns(request.Object); 
context.SetupGet(x => x.Response).Returns(response.Object); 

var routes = new RouteCollection(); 
MvcApplication.RegisterRoutes(routes); 
var helper = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes); 
+0

Идеальный ответ для меня, спасибо Стивен! – jhilden

Смежные вопросы