NET MVC: 使用 UrlHelper 的单元测试控制器

我的一个控制器操作(在 Ajax 请求中调用的一个操作)是向客户端返回一个 URL,这样它就可以执行重定向。我正在使用 Url.RouteUrl(..),在我的单元测试期间,由于 Controller.Url参数没有预先填充,这个操作失败了。

我尝试了很多方法,其中包括尝试存根 UrlHelper(失败了) ,手动创建一个具有存根 HttpContextBase(在 RouteCollection.GetUrlWithApplicationPath调用中失败了)的 RequestContextUrlHelper

我在谷歌上搜索了一下,但实际上没有找到任何关于这个主题的内容。我是否在控制器操作中使用 Url.RouteUrl做了一些非常愚蠢的事情?有更简单的办法吗?

更糟糕的是,我希望能够在我的单元测试中测试返回的 URL ——事实上我只对知道它重定向到正确的路由感兴趣,但是因为我返回的是一个 URL 而不是一个路由,我希望能够控制被解析的 URL (例如,使用一个截断的 RouteCollection)——但是我很高兴我的测试能够通过。

37436 次浏览

下面是我的一个测试(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);

如果您想模拟 HttpContextBase 类,这篇文章可能会很有用。

Http://www.hanselman.com/blog/aspnetmvcsessionatmix08tddandmvcmockhelpers.aspx

根据@eu-ge-ne 给出的答案,我得到了很大的帮助:

我有一个执行重定向的 ActionResult,以及一个带有 FormCollection 参数的 UpdateModel 调用。要使 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);

Http://kbochevski.blogspot.com/2010/06/unit-testing-mvcnet.html 讨论了如何使用单元测试覆盖所有层。谷歌上的源代码可能会有很大的帮助。

一个来自 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);