我将如何测试WebApi / MVC项目中的方法或控制器的授权属性是否具有特定角色
所以我可以测试一个像下面这样的方法?
[Test]
[TestCase("Put", new []{"Admin","TeamMember"})]
[TestCase("Post", new []{"Admin","TeamMember"})]
[TestCase("Get", new []{"TeamMember"})]
public void Ensure_Methods_have_Correct_Roles(string methodToTest, List<string> roles)
{
var controller = new myController();
Assert.IsTrue(controller.HasRoles(methodToTest, roles));
}
使用Roles扩展方法就像这样删除了
public static bool HasRoles(this Controller controller, string action, string[] roles)
{
var controllerType = controller.GetType();
var method = controllerType.GetMethod(action);
object[] filters = method.GetCustomAttributes(typeof(AuthorizationAttribute), true);
if(!filters.Any(x => x.GetType() == typeof(AuthorizationAttribute))
{
throw exception()
}
var rolesOnCurrentMethodsAttribute = // This is where i'm stuck
foreach(var role in rolesOnCurrentMethodsAttribute)
{
//pseudo-code
if(!roles.contains(role)
{
return false;
}
}
return true;
}
这是否合情合理还是应该直接测试控制器动作并测试响应是否为401/403?这需要模拟上下文,并且意味着更多的测试代码,因为我必须分别测试每个方法.
编辑:也许不关注它是否明智.它是可行的吗?
我的想法是,单元测试将是规范哪些操作应该具有哪些角色的规范(因为目前没有书面规范,并且可能永远不会有一个).如果开发人员更改了角色,那么他们需要有充分的理由.
编辑#2
根据下面的Con的答案,这就是我最终得到的,一种检查动作的方法,另一种检查控制器的方法.
public static bool WebApiActionHasRoles(this ApiController controller, string action, string roles)
{
var controllerType = controller.GetType();
var method = controllerType.GetMethod(action);
object[] filters = method.GetCustomAttributes(typeof(System.Web.Http.AuthorizeAttribute), true);
if (!filters.Any())
{
throw new Exception();
}
var rolesOnCurrentMethodsAttribute = filters.SelectMany(attrib => ((System.Web.Http.AuthorizeAttribute)attrib).Roles.Split(new[] { ',' })).ToList();
var rolesToCheckAgainst = roles.Split(',').ToList();
return !rolesOnCurrentMethodsAttribute.Except(rolesToCheckAgainst).Any() && !rolesToCheckAgainst.Except(rolesOnCurrentMethodsAttribute).Any();
}
public static bool WebApiControllerHasRoles(this ApiController controller, string roles)
{
var controllerType = controller.GetType();
object[] filters = controllerType.GetCustomAttributes(typeof(System.Web.Http.AuthorizeAttribute), true);
if (!filters.Any())
{
throw new Exception();
}
var rolesOnCurrentMethodsAttribute = filters.SelectMany(attrib => ((System.Web.Http.AuthorizeAttribute)attrib).Roles.Split(new[] { ',' })).ToList();
var rolesToCheckAgainst = roles.Split(',').ToList();
return !rolesOnCurrentMethodsAttribute.Except(rolesToCheckAgainst).Any() && !rolesToCheckAgainst.Except(rolesOnCurrentMethodsAttribute).Any();
}
如果要将其与MVC而不是Web Api控制器/ Actions一起使用,只需将System.Web.Http.AuthorizeAttribute更改为System.Web.MVC.AuthorizeAttribute,并在Method Signature中将ApiController更改为Controller
最佳答案 如果您指的是AuthorizeAttribute vs AuthorizationAttribute,那么这就是您所需要的:
public static bool HasRoles(this Controller controller, string action, string[] roles)
{
var controllerType = controller.GetType();
var method = controllerType.GetMethod(action);
object[] filters = method.GetCustomAttributes(typeof(AuthorizeAttribute), true);
if(!filters.Any())
{
throw new Exception();
}
var rolesOnCurrentMethodsAttribute = filters.SelectMany(attrib => ((AuthorizeAttribute)attrib).Roles.Split(new[] { ',' })).ToList();
return roles.Except(rolesInMethod).Count() == 0 && rolesInMethod.Except(roles).Count() == 0;
}
或者,如果您希望使测试更严格,并且每个操作仅强制执行一个Authorize属性:
public static bool HasRoles(this Controller controller, string action, string roles)
{
var controllerType = controller.GetType();
var method = controllerType.GetMethod(action);
var attrib = method.GetCustomAttributes(typeof(AuthorizeAttribute), true).FirstOrDefault() as AuthorizeAttribute;
if (attrib == null)
{
throw new Exception();
}
return attrib.Roles == roles;
}