我遇到的问题是UrlHelper的RouteUrl方法在我的测试中运行时只返回一个空字符串,尽管在真正的HttpContext中执行时功能正常。然而,它正在寻找路线 - 如果我尝试解决尚未定义的路线名称,我会正确地获得异常。
我使用code provided by Scott Hanselman/Kzu嘲笑了HttpContext和朋友,并将code needed to bootstrap the Application's Routes添加到了模拟实例中
为了减少我的情况中的变量数量,我写了一个简单的测试:
[Test]
public void UrlHelperReturnsCorrectUrl()
{
var controller = new MyController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path", controller.Url.RouteUrl("MyRoute"));
}
有趣的是,直接访问RouteCollection并使用VirtualPath确实有效:
[Test]
public void GetVirtualPathReturnsCorrectUrl()
{
var controller = new AccountController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path",
Controller.Url.RouteCollection["MyRoute"]
.GetVirtualPath(
controller.Url.RequestContext,
new RouteValueDictionary())
.VirtualPath);
}
供参考,这是我对LoadUrlHelper扩展方法的实现:
public static Controller LoadUrlHelper(this Controller controller)
{
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
controller.Url = new UrlHelper(
controller.ControllerContext.RequestContext,
routes);
return controller;
}
这是我在应用程序的Global.asax中定义的路线:
routes.MapRoute(
"MyRoute", "My/Route/Path",
new {controller = "Home", action = "Index"});
有没有人碰到这个?我错过了什么吗?
编辑:
我已经遵循了MVC代码,直到它将路由处理交给System.Routing并发现了一些非常有趣的东西。 MVC最终运行以查找所需URL的代码(当然是压缩的)返回一个空字符串:
Controller.Url.RouteCollection.GetVirtualPath(
Controller.Url.RequestContext,
"MyRoute", new RouteValueDictionary()).VirtualPath;
而非常相似的变量返回预期的字符串:
Controller.Url.RouteCollection["MyRoute"].GetVirtualPath(
Controller.Url.RequestContext,
new RouteValueDictionary()).VirtualPath;
我似乎无法在底层代码中进一步了解这里实际发生的事情,但认为它可能有助于某人了解我缺少的设置。 (我不打算大吼大叫,因为事实证明UrlHelpers在真正的HttpContext中工作时)
答案 0 :(得分:1)
我的问题的解决方案已发布到another SO question。
我曾尝试过这种解决方案早餐,但做得很差。一旦我完全复制并根据我的情况进行了修改,它就完美无缺。
这是一个更通用的版本,可以在许多测试中重复使用(如果放在基础测试夹具类或类似的东西中)。
用法:
var controller = GetController<MyController>();
controller.MyAction();
//...
方法:
protected T GetController<T>() where T : Controller, new()
{
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", 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(It.IsAny<string>())).Returns((string p) => p);
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 T();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
return controller;
}