【发布时间】:2014-11-25 12:55:15
【问题描述】:
我将如何测试 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));
}
将 has 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 控制器/操作,只需将 System.Web.Http.AuthorizeAttribute 更改为 System.Web.MVC.AuthorizeAttribute 并在方法签名中将 ApiController 更改为 Controller
【问题讨论】:
-
根据您的代码,我认为您所做的只是测试 AuthorizeAttribute 是否有效,这是 Microsoft 的责任。一个集成测试断言你得到一个 401/403 是好的 - 但测试一个控制器操作可能就足够了。
-
我不同意。我正在测试一个特定的方法是否具有一组指定的角色。或者至少这就是我想要做的......:)
-
我也想过。如果您要更改方法的角色,这可能是您打算做的事情,而您必须确保测试现在与更改匹配,从而导致不必要的工作。
-
我看到了围绕允许的角色进行单元测试的价值。当允许的角色发生意外更改时,最好让单元测试失败(并修复)。
标签: c# asp.net asp.net-mvc unit-testing asp.net-web-api