【问题标题】:MVC custom filter, invoke ASP.NET pipeline event manually for unit testMVC 自定义过滤器,手动调用 ASP.NET 管道事件进行单元测试
【发布时间】: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

【问题讨论】:

    标签: asp.net asp.net-mvc-3 unit-testing events protected


    【解决方案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 在控制器构造函数中为空。
    猜你喜欢
    • 2015-01-23
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多