【问题标题】:c# WebApi how to unit test if a controller action is decorated with an authorization attribute with specific argumentsc#WebApi如何对控制器操作是否使用具有特定参数的授权属性进行单元测试
【发布时间】:2019-03-29 22:41:56
【问题描述】:

我们有一个自定义 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());
    }
}

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

【问题讨论】:

    标签: c# asp.net-web-api authorization


    【解决方案1】:

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

    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)));
    }
    

    用法:

    [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();
    }
    

    【讨论】:

    • 干得好,这是解决这个问题的好方法。
    猜你喜欢
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多