ASP.NET MVC:Mock controller.Url.Action

时间:2022-05-31 09:26:31

Urls for menus in my ASP.NET MVC apps are generated from controller/actions. So, they call

我的ASP.NET MVC应用程序中的菜单的URL是从控制器/操作生成的。所以,他们打电话

controller.Url.Action(action, controller)

Now, how do I make this work in unit tests? I use MVCContrib successfully with

现在,我如何在单元测试中完成这项工作?我成功使用MVCContrib

var controller = new TestControllerBuilder().CreateController<OrdersController>();

but whatever I try to do with it I get controller.Url.Action(action, controller) failing with NullReferenceException because Url == null.

但无论我尝试用它做什么,我都会得到controller.Url.Action(动作,控制器)失败并且NullReferenceException因为Url == null。

Update: it's not about how to intercept HttpContext. I did this in several ways, using MVCContrib, Scott Hanselman's example of faking, and also the one from http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx. This doesn't help me because I need to know WHAT values to fake... is it ApplicationPath? How do I set it up? Does it need to match the called controller/action? That is, how do Url.Action works and how do I satisfy it?

更新:它不是关于如何拦截HttpContext。我通过几种方式做到了这一点,使用MVCContrib,Scott Hanselman的假装示例,以及http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking -THE-控制器context.aspx。这对我没有帮助,因为我需要知道假的值是什么......是ApplicationPath吗?我该如何设置?是否需要匹配被调用的控制器/动作?也就是说,Url.Action如何工作以及如何满足它?

Also, I know I can do IUrlActionAbstraction and go with it... but I'm not sure I want to do this. After all, I have MVCContrib/Mock full power and why do I need another abstraction.

此外,我知道我可以做IUrlActionAbstraction并继续使用它...但我不确定我是否想这样做。毕竟,我有MVCContrib / Mock全功率,为什么我需要另一个抽象。

4 个解决方案

#1


21  

Here's how you could mock UrlHelper using MvcContrib's TestControllerBuilder:

以下是使用MvcContrib的TestControllerBuilder模拟UrlHelper的方法:

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


15  

A cleaner way to do this is just use Moq(or any other framework you like) to Mock UrlHelper itself

更简洁的方法是使用Moq(或任何其他你喜欢的框架)来模拟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);

clean and simple.

干净简单。

#3


3  

Fake it easy works nicely:

假它很容易很好地工作:

 var fakeUrlHelper = A.Fake<UrlHelper>();
        controller.Url = fakeUrlHelper;
        A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored))
            .Returns("/Action/Controller");

#4


3  

If you're using Moq (and not MvcContrib's TestControllerBuilder), you can mock out the context, similar to @DarianDimitrov's answer:

如果您正在使用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()
);

This doesn't set the controller.HttpContext property, but it does allow Url.Action to execute (and return an empty string -- no mocking required).

这不会设置controller.HttpContext属性,但它允许Url.Action执行(并返回一个空字符串 - 不需要模拟)。

#1


21  

Here's how you could mock UrlHelper using MvcContrib's TestControllerBuilder:

以下是使用MvcContrib的TestControllerBuilder模拟UrlHelper的方法:

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


15  

A cleaner way to do this is just use Moq(or any other framework you like) to Mock UrlHelper itself

更简洁的方法是使用Moq(或任何其他你喜欢的框架)来模拟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);

clean and simple.

干净简单。

#3


3  

Fake it easy works nicely:

假它很容易很好地工作:

 var fakeUrlHelper = A.Fake<UrlHelper>();
        controller.Url = fakeUrlHelper;
        A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored))
            .Returns("/Action/Controller");

#4


3  

If you're using Moq (and not MvcContrib's TestControllerBuilder), you can mock out the context, similar to @DarianDimitrov's answer:

如果您正在使用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()
);

This doesn't set the controller.HttpContext property, but it does allow Url.Action to execute (and return an empty string -- no mocking required).

这不会设置controller.HttpContext属性,但它允许Url.Action执行(并返回一个空字符串 - 不需要模拟)。