ASP.NET MVC: Контроллеры модулей тестирования, использующие UrlHelper

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

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

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

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

Ответ 1

Вот один из моих тестов (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

Измененная реализация от 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);

Ответ 4

Построение ответа от @eu-ge-ne, которое мне очень помогло:

У меня был ActionResult, который сделал перенаправление, а также имел вызов UpdateModel с параметром FormCollection. Для работы UpdateModel() мне пришлось добавить это в мою Mocked 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);

Ответ 5

http://kbochevski.blogspot.com/2010/06/unit-testing-mvcnet.html обсуждает, как покрыть все слои модульными тестами. Он использует Rhino и MVC.Contrib для тестирования контроллеров. Исходный код в google может оказать большую помощь.