MVC 自定义过滤器,手动调用 ASP.NET 管道事件进行单元测试

Posted

技术标签:

【中文标题】MVC 自定义过滤器,手动调用 ASP.NET 管道事件进行单元测试【英文标题】:MVC custom filter, invoke ASP.NET pipeline event manually for unit test 【发布时间】:2012-01-26 17:08:00 【问题描述】:
public abstract class MyControllerBase : Controller

    protected override void OnActionExecuting(ActionExecutingContext context)
    
        // do some magic
    

我所有的控制器都继承自 MyControllerBase。问题是现在我无法对某些方法进行单元测试,因为过滤器设置了一些影响代码路径的授权/逻辑标志。

有没有办法手动触发OnActionExecuting?管道如何触发这些事件?

编辑:更多地展示这个设计背后的想法,以响应 cmets。我基本上是这样的:

public abstract class MyControllerBase : Controller

    protected override void OnActionExecuting(ActionExecutingContext context)
    
        UserProperties = 
             _userService
                .GetUserProperties(filterContext.HttpContext.User.Identity.Name);

        ViewBag.UserProperties = UserProperties;
    

    public UserProperties  get; private set; 

    public bool CheckSomethingAboutUser()
    
         return UserProperties != null 
            && UserProperties.IsAuthorisedToPerformThisAction;
    

    // ... etc, other methods for querying UserProperties

所以现在在ViewController 的任何地方,我都可以获取当前用户的详细信息、他们的电子邮件地址、他们的授权、他们工作的部门等等。

例子:

public class PurchasingController : MyControllerBase 

    public ActionResult RaisePurchaseOrder(Item item)
    
        // can use UserProperties from base class to determine correct action...

        if (UserProperties.CanRaiseOrders)

        if (UserProperties.Department == item.AllocatedDepartment)
    

所以这个设计真的很好用,但正如你所见,测试上述动作很困难,因为我无法在测试设置中直接操作UserProperties

【问题讨论】:

【参考方案1】:

我不确定你是否应该像在 MCV 中那样覆盖 OnActionExecuting,通常我会创建一个 ActionFilterAttribute

public class SomeMagicAttribute : ActionFilterAttribute

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    

    

那么你的班级:

[SomeMagic]
public abstract class MyControllerBase : Controller



然后在你的单元测试中你可以这样做

var magic = new SomeMagicAttribute();
var simulatedContext = new ActionExecutingContext();
magic.OnActionExecuting(simulatedContext);

【讨论】:

这里的问题是,在OnActionExecuting 事件中,我将一些标志写入ViewBagMyControllerBase 中的公共属性。这个想法是这些值现在在所有控制器和视图中随处可用。我的记忆有点模糊,但我想我选择了我的设计,因为我看不出使用自定义 ActionFilterAttribute 是如何实现的。你有什么想法吗? 你能发布一些你的OnActionExecuting 的魔法吗? - 至少要在 viewbag 中设置东西,你可以这样做filterContext.Controller.ViewBag.magic = 42; 我已更新问题以展示设计背后的理念。 OnActionExecuting 没有做任何聪明的事,它只是访问一些我想在全球范围内提供的用户信息。如果您认为我做错了,您的 cmets 将不胜感激。 不,你的做法没有错,事实上我只是检查了我正在处理的 MVC 项目,我们的做法非常相似。 - 无论如何,从您的代码示例来看,您似乎并不需要ActionExecutingContext,因此您可以在基本构造函数中使用HttpContext.User.Identity.Name 填充UserProperties 变量,对吧? 不幸的是,这不起作用,因为HttpContext 在控制器构造函数中为空。

以上是关于MVC 自定义过滤器,手动调用 ASP.NET 管道事件进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

asp.net mvc 自定义全局过滤器 验证用户是否登录

ASP.NET MVC

ASP.NET MVC Ajax 错误处理

asp.net mvc 中怎么像webform一样自定义一个BaseController实现判断用户是不是登录 然后获取用户的权限

ASP.NET MVC 之自定义HtmlHelper

ASP.NET Core MVC 过滤器介绍