猿问

如何使用构造函数参数测试动作过滤器的存在?

我正在尝试测试我的基本控制器是否装饰有特定的动作过滤器。因为此过滤器的构造函数看上去像web.config,所以我的第一个测试尝试失败,因为测试项目没有有效的配置文件。继续,我使用了TestConfigProvider我注入到过滤器构造函数中的a,但是以下测试失败了,因为未将配置提供程序传递给构造函数。我还能如何测试是否应用了此过滤器?


[TestMethod]

public void Base_controller_must_have_MaxLengthFilter_attribute()

{

    var att = typeof(BaseController).GetCustomAttribute<MaxLengthFilter>();

    Assert.IsNotNull(att);

}


FFIVE
浏览 583回答 3
3回答

九州编程

好的,您已经迈出了很好的第一步,认识到Web.config只是另一个依赖项,并将其包装到ConfigProvider中进行注入是一个很好的解决方案。但是,您开始陷入MVC的设计问题之一-即,为了实现DI友好性,属性应仅提供元数据,而从不实际定义行为。这不是测试方法的问题,而是滤波器设计方法的问题。正如文章中指出的那样,您可以通过将操作过滤器属性分为两部分来解决此问题。该属性不包含任何用于标记控制器和操作方法的行为。一个DI友好类,该类实现IActionFilter并包含所需的行为。该方法是使用IActionFilter来测试属性的存在,然后执行所需的行为。可以为动作过滤器提供所有依赖项,然后在组成应用程序时将其注入。IConfigProvider provider = new WebConfigProvider();IActionFilter filter = new MaxLengthActionFilter(provider);GlobalFilters.Filters.Add(filter);注意:如果您需要过滤器的任何依赖项以使生命周期短于单例,则需要GlobalFilterProvider在此答案中使用as 。MaxLengthActionFilter的实现如下所示:public class MaxLengthActionFilter : IActionFilter{&nbsp; &nbsp; public readonly IConfigProvider configProvider;&nbsp; &nbsp; public MaxLengthActionFilter(IConfigProvider configProvider)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (configProvider == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentNullException("configProvider");&nbsp; &nbsp; &nbsp; &nbsp; this.configProvider = configProvider;&nbsp; &nbsp; }&nbsp; &nbsp; public void OnActionExecuted(ActionExecutedContext filterContext)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var attribute = this.GetMaxLengthAttribute(filterContext.ActionDescriptor);&nbsp; &nbsp; &nbsp; &nbsp; if (attribute != null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var maxLength = attribute.MaxLength;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Execute your behavior here, and use the configProvider as needed&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public void OnActionExecuting(ActionExecutingContext filterContext)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var attribute = this.GetMaxLengthAttribute(filterContext.ActionDescriptor);&nbsp; &nbsp; &nbsp; &nbsp; if (attribute != null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var maxLength = attribute.MaxLength;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Execute your behavior here, and use the configProvider as needed&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public MaxLengthAttribute GetMaxLengthAttribute(ActionDescriptor actionDescriptor)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; MaxLengthAttribute result = null;&nbsp; &nbsp; &nbsp; &nbsp; // Check if the attribute exists on the controller&nbsp; &nbsp; &nbsp; &nbsp; result = (MaxLengthAttribute)actionDescriptor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .ControllerDescriptor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GetCustomAttributes(typeof(MaxLengthAttribute), false)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .SingleOrDefault();&nbsp; &nbsp; &nbsp; &nbsp; if (result != null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // NOTE: You might need some additional logic to determine&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; // which attribute applies (or both apply)&nbsp; &nbsp; &nbsp; &nbsp; // Check if the attribute exists on the action method&nbsp; &nbsp; &nbsp; &nbsp; result = (MaxLengthAttribute)actionDescriptor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GetCustomAttributes(typeof(MaxLengthAttribute), false)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .SingleOrDefault();&nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; }}并且,不应包含任何行为的属性应如下所示:// This attribute should contain no behavior. No behavior, nothing needs to be injected.[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]public class MaxLengthAttribute : Attribute{&nbsp; &nbsp; public MaxLengthAttribute(int maxLength)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; this.MaxLength = maxLength;&nbsp; &nbsp; }&nbsp; &nbsp; public int MaxLength { get; private set; }}使用更宽松的耦合设计,测试属性的存在要简单得多。[TestMethod]public void Base_controller_must_have_MaxLengthFilter_attribute(){&nbsp; &nbsp; var att = typeof(BaseController).GetCustomAttribute<MaxLengthAttribute>();&nbsp; &nbsp; Assert.IsNotNull(att);}

慕码人8056858

最近,我在这里关于配置“问题”的问题越来越多。它们都有一个共同的基础-您有几个需要使用相同配置的项目,服务器和服务。我的建议是-停止使用Web.config。将所有配置放入数据库!添加一个包含所有配置键和值的表(或几个表),并在应用程序启动时读取它们(global.asax)。这样,您不必担心将配置配置到每个项目中或将其注入到不同的构造函数中。

白板的微信

实际上,如果您正确地设计了过滤器,那不是不可以的(有理由将它们称为过滤器)。筛选器的目的仅是确定何时执行共享行为,而不应实际执行共享行为。应该将其委派给一个处理程序,该处理程序的派生方式与ActionResult Microsoft在AuthorizeAttribute中所做的一样(filterContext.Result仅当需要运行时才进行设置)。
随时随地看视频慕课网APP
我要回答