c#WebApi如何单元测试控制器操作是否使用带有特定参数的授权属性进行修饰

c#WebApi如何单元测试控制器操作是否使用带有特定参数的授权属性进行修饰,c#,asp.net-web-api,authorization,C#,Asp.net Web Api,Authorization,我们有一个自定义的AuthorizationFilterAttribute,用于修饰WebApi控制器操作,该操作使用枚举参数来定义访问级别 public enum AuthLevel { Any = 1, Client = 2, Server = 4 } [AttributeUsage(AttributeTargets.Method)] public class CustomAuthorizeAttribute : AuthorizationFilterAttribu

我们有一个自定义的
AuthorizationFilterAttribute
,用于修饰WebApi控制器操作,该操作使用枚举参数来定义访问级别

public enum AuthLevel
{
    Any = 1,
    Client = 2,
    Server = 4
}

[AttributeUsage(AttributeTargets.Method)]
public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
{
    private readonly AuthLevel _authLevel;

    public CustomAuthorizeAttribute(AuthLevel authLevel)
    {
        _authLevel = authLevel;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        ...
    }
}
用法:

public class TestController : ApiController
{
    [HttpGet, Route("api/test")]
    [CustomAuthorizeAttribute(AuthLevel.Client)]
    public IHttpActionResult Get()
    {
        return Ok();
    }

    [HttpGet, Route("api/testasync")]
    [CustomAuthorizeAttribute(AuthLevel.Server)]
    public async Task<IHttpActionResult> GetAsync()
    {
        return Task.FromResult(Ok());
    }
}
[Test]
public void Get_HasCorrectAuthLevel()
{
    var controller = new TestController();
    controller.HasExpectedAuthLevel(c => c.Get(), AuthLevel.Client).Should().BeTrue();
    controller.HasExpectedAuthLevel(c => c.GetAsync(), AuthLevel.Server).Should().BeTrue();
}
公共类TestController:ApiController
{
[HttpGet,路由(“api/测试”)]
[CustomAuthorizeAttribute(AuthLevel.Client)]
public IHttpActionResult Get()
{
返回Ok();
}
[HttpGet,路由(“api/testasync”)]
[CustomAuthorizeAttribute(AuthLevel.Server)]
公共异步任务GetAsync()
{
返回Task.FromResult(Ok());
}
}

虽然良好的集成测试无法替代,但我希望能够使用正确的枚举值对控制器操作定义此属性进行单元测试。它还必须同时使用标准方法和异步方法。

我为此创建了两个扩展方法:

public static bool HasExpectedAuthLevel<T>(this T controller, Expression<Action<T>> action, AuthLevel expectedAuthLevel)
    where T : ApiController
{
    return controller.HasAttributeWithExpectedArgument(action, typeof(CustomAuthorizeAttribute), expectedAuthLevel);
}

public static bool HasExpectedAuthLevel<T>(this T controller, Expression<Func<T, Task>> action, AuthLevel expectedAuthLevel)
    where T : ApiController
{
    return controller.HasAttributeWithExpectedArgument(action, typeof(CustomAuthorizeAttribute), expectedAuthLevel);
}

public static bool HasAttributeWithExpectedArgument<TController, TArgument>(this TController controller, Expression<Action<TController>> action, Type attributeType, TArgument expectedArgument)
    where TController : ApiController
{
    return HasAttributeWithExpectedArgument(action?.Body as MethodCallExpression, attributeType, expectedArgument);
}

public static bool HasAttributeWithExpectedArgument<TController, TArgument>(this TController controller, Expression<Func<TController, Task>> action, Type attributeType, TArgument expectedArgument)
    where TController : ApiController
{
    return HasAttributeWithExpectedArgument(action?.Body as MethodCallExpression, attributeType, expectedArgument);
}

private static bool HasAttributeWithExpectedArgument<TArgument>(MethodCallExpression action, Type attributeType, TArgument expectedArgument)
{
    if (action == null || !attributeType.IsSubclassOf(typeof(Attribute)))
    {
        return false;
    }

    var attributesData = action.Method.GetCustomAttributesData().Where(a => a.AttributeType == attributeType).ToArray();

    return attributesData.Any(attribute =>
        attribute.ConstructorArguments.Any(arg =>
            arg.ArgumentType == typeof(TArgument) && EqualityComparer<TArgument>.Default.Equals((TArgument)arg.Value, expectedArgument)));
}

干得好,这是解决这个问题的好办法。