我如何testing与构造函数参数的行动filter的存在?

我试图testing我的基础控制器是用特定的动作filter装饰的。 因为这个filter的构造函数看起来web.config ,我第一次尝试在testing失败,因为testing项目没有一个有效的configuration文件。 继续前进,我使用了一个我注入到filter构造函数的TestConfigProvider ,但是下面的testing失败,因为configuration提供者没有传递给构造函数。 我还可以testing这个filter是否被应用?

 [TestMethod] public void Base_controller_must_have_MaxLengthFilter_attribute() { var att = typeof(BaseController).GetCustomAttribute<MaxLengthFilter>(); Assert.IsNotNull(att); } 

那么,你已经采取了一个良好的第一步,认识到Web.config只是另一个依赖和包装到一个ConfigProvider注入是一个很好的解决scheme。

但是,你正在被MVC的一个devise问题绊倒 – 也就是说,DI是友好的,属性只应该提供元数据,而不是实际定义行为 。 这与您的testing方法不是问题,这是filterdevise方法的一个问题。

正如在post中指出的,你可以通过将你的action filter属性分成两部分来解决这个问题。

  1. 不包含标记控制器和操作方法的行为的属性。
  2. 一个DI友好的类,实现IActionFilter并包含所需的行为。

该方法是使用IActionFilter来testing该属性的存在,然后执行所需的行为。 动作filter可以提供所有的依赖关系,然后在构build应用程序时注入。

 IConfigProvider provider = new WebConfigProvider(); IActionFilter filter = new MaxLengthActionFilter(provider); GlobalFilters.Filters.Add(filter); 

注意:如果您需要任何筛选器的依赖项的生命周期比singleton短,您将需要使用GlobalFilterProvider作为此答案 。

MaxLengthActionFilter的实现看起来像这样:

 public class MaxLengthActionFilter : IActionFilter { public readonly IConfigProvider configProvider; public MaxLengthActionFilter(IConfigProvider configProvider) { if (configProvider == null) throw new ArgumentNullException("configProvider"); this.configProvider = configProvider; } public void OnActionExecuted(ActionExecutedContext filterContext) { var attribute = this.GetMaxLengthAttribute(filterContext.ActionDescriptor); if (attribute != null) { var maxLength = attribute.MaxLength; // Execute your behavior here, and use the configProvider as needed } } public void OnActionExecuting(ActionExecutingContext filterContext) { var attribute = this.GetMaxLengthAttribute(filterContext.ActionDescriptor); if (attribute != null) { var maxLength = attribute.MaxLength; // Execute your behavior here, and use the configProvider as needed } } public MaxLengthAttribute GetMaxLengthAttribute(ActionDescriptor actionDescriptor) { MaxLengthAttribute result = null; // Check if the attribute exists on the controller result = (MaxLengthAttribute)actionDescriptor .ControllerDescriptor .GetCustomAttributes(typeof(MaxLengthAttribute), false) .SingleOrDefault(); if (result != null) { return result; } // NOTE: You might need some additional logic to determine // which attribute applies (or both apply) // Check if the attribute exists on the action method result = (MaxLengthAttribute)actionDescriptor .GetCustomAttributes(typeof(MaxLengthAttribute), false) .SingleOrDefault(); return result; } } 

而且, 不应该包含任何行为的属性应该如下所示:

 // This attribute should contain no behavior. No behavior, nothing needs to be injected. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] public class MaxLengthAttribute : Attribute { public MaxLengthAttribute(int maxLength) { this.MaxLength = maxLength; } public int MaxLength { get; private set; } } 

通过更松散的耦合devise,对属性的存在性进行testing要简单得多。

 [TestMethod] public void Base_controller_must_have_MaxLengthFilter_attribute() { var att = typeof(BaseController).GetCustomAttribute<MaxLengthAttribute>(); Assert.IsNotNull(att); } 

也许你可以添加有效的configuration文件到你的testing项目通过“添加文件作为链接” 在这里输入图像描述在这里输入图像描述

最近我这里关于configuration“问题”的问题越来越多。 他们都有一个共同的基础 – 你有几个项目,服务器,服务需要使用相同的configuration。 我build议你 – 停止使用Web.config。

将所有configuration放入数据库! 添加一个包含所有configuration键的表(或者几个表),并在应用程序启动时读取它们(global.asax)。

这样你就不必担心你的configuration会被应用到每个项目或者注入到不同的构造函数中。