如何对 Web API 2 的防伪令牌筛选器进行单元测试

本文关键字:筛选 令牌 单元测试 Web API | 更新日期: 2023-09-27 18:32:59

我正在尝试使用自定义过滤器的MsTest编写单元测试用例,该过滤器具有在WEB API 2项目中验证POST方法Antiforgerytoken ASP.NET 逻辑。

[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        try
        {
            string cookieToken = null;
            string formToken = null;
            if (actionContext.Request.IsAjaxRequest())
            {
                IEnumerable<string> tokenHeaders;
                if (actionContext.Request.Headers.TryGetValues("__RequestVerificationToken", out tokenHeaders))
                {
                    string[] tokens = tokenHeaders.First().Split(':');
                    if (tokens.Length == 2)
                    {
                        cookieToken = tokens[0].Trim();
                        formToken = tokens[1].Trim();
                    }
                }
                if (cookieToken != null && formToken !=null)
                {
                    AntiForgery.Validate(cookieToken, formToken);
                }
                else
                {
                    AntiForgery.Validate();
                }                    
            }
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(ex);
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
        }            
    }
}

在下面的代码中IsAjaxRequest是一个扩展方法

public static class HttpRequestMessageExtensions
{
    public static bool IsAjaxRequest(this HttpRequestMessage request)
    {
        IEnumerable<string> headers;
        if (request.Headers.TryGetValues("X-Requested-With", out headers))
        {
            var header = headers.FirstOrDefault();
            if (!string.IsNullOrWhiteSpace(header))
            {
                return header.ToLowerInvariant() == "xmlhttprequest";
            }
        }
        return false;
    }
}

在这里,我的问题是如何模拟IsAjaxRequest以及如何actionContext参数传递给OnActionExecuting方法。

谁能帮我提供一些关于此的代码示例?

如何对 Web API 2 的防伪令牌筛选器进行单元测试

IsAjaxRequest是一个扩展方法,这意味着它是一个静态方法。

你不应该嘲笑静态方法。应将其作为受测方法行为的一部分进行测试。

以下示例显示了如何测试无效请求:(我删除了 :: ErrorSignal.FromCurrentContext().Raise(ex);,因为我不知道要添加哪个程序集......所以在您的测试中添加缺少的断言''s...

[TestMethod]
public void TestMethod1()
{
    var target = new ValidateJsonAntiForgeryTokenAttribute();
    var requestMessage = new HttpRequestMessage();
    requestMessage.Headers.Add("X-Requested-With", new[] {"xmlhttprequest"});
    var fakeDescriptor = new Mock<HttpActionDescriptor>();
    var controllerContext = new HttpControllerContext {Request = requestMessage};
    var context = new HttpActionContext(controllerContext, fakeDescriptor.Object);

    target.OnActionExecuting(context);

    Assert.AreEqual(HttpStatusCode.Forbidden, actionContext.Response.StatusCode);
}

如果你真的需要,你可以模拟静态方法。这是我使用 Typemock 隔离器的测试示例:

[TestMethod, Isolated]
public void TestValidate()
{
    //How to fake action context to further passing it as a parameter:
    var fake = Isolate.Fake.AllInstances<HttpActionContext>();
    Isolate.Fake.StaticMethods<HttpActionContext>();
    //How to mock IsAjaxRequset:
    var request = new HttpRequestMessage();
    Isolate.WhenCalled(() => request.IsAjaxRequest()).WillReturn(true);            
    //Arrange:
    ValidateJsonAntiForgeryTokenAttribute target = new ValidateJsonAntiForgeryTokenAttribute();
    Isolate.WhenCalled(() => AntiForgery.Validate()).IgnoreCall();
    //Act:
    target.OnActionExecuting(fake);
    //Assert:
    Isolate.Verify.WasCalledWithAnyArguments(() => AntiForgery.Validate());
}