c# WebApi how to unit test if a controller action is decorated with an authorization attribute with specific arguments

这一生的挚爱 提交于 2019-12-13 04:16:45

问题


We have a custom AuthorizationFilterAttribute for decorating WebApi controller actions that takes an enum parameter to define the level of access.

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)
    {
        ...
    }
}

Usage:

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

While there's no substitution for good integration tests, I'd like to be able to unit test that this attribute has been defined on the controller action with the correct enum value. It also has to work with both standard and async methods.


回答1:


I created a couple of extension methods for this:

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

Usage:

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


来源:https://stackoverflow.com/questions/55419864/c-sharp-webapi-how-to-unit-test-if-a-controller-action-is-decorated-with-an-auth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!