Unit test WebApi2 passing header values

醉酒当歌 提交于 2019-12-04 17:01:50

I believe that you should avoid reading the headers in your controller for better separation of concerns (you don't need to read the Customer from request body in the controller right?) and testability.

How I will do it is create a CustomerId class (this is optional. see note below) and CustomerIdParameterBinding

public class CustomerId
{
    public string Value { get; set; }
}

public class CustomerIdParameterBinding : HttpParameterBinding
{
    public CustomerIdParameterBinding(HttpParameterDescriptor parameter) 
    : base(parameter)
    {
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        actionContext.ActionArguments[Descriptor.ParameterName] = new CustomerId { Value = GetIdOrNull(actionContext) };
        return Task.FromResult(0);
    }

    private string GetIdOrNull(HttpActionContext actionContext)
    {
        IEnumerable<string> idValues;
        if(actionContext.Request.Headers.TryGetValues("customerId", out idValues))
        {
            return idValues.First();
        }
        return null;
    }
}

Writing up the CustomerIdParameterBinding

config.ParameterBindingRules.Add(p =>
{
    return p.ParameterType == typeof(CustomerId) ? new CustomerIdParameterBinding(p) : null;
});

Then in my controller

public void Post(CustomerId id, Customer customer)

Testing the Parameter Binding

public void TestMethod()
{
    var parameterName = "TestParam";
    var expectedCustomerIdValue = "Yehey!";

    //Arrange
    var requestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri");
    requestMessage.Headers.Add("customerId", expectedCustomerIdValue );

    var httpActionContext = new HttpActionContext
    {
        ControllerContext = new HttpControllerContext
        {
            Request = requestMessage
        }
    };

    var stubParameterDescriptor = new Mock<HttpParameterDescriptor>();
    stubParameterDescriptor.SetupGet(i => i.ParameterName).Returns(parameterName);

    //Act
    var customerIdParameterBinding = new CustomerIdParameterBinding(stubParameterDescriptor.Object);
    customerIdParameterBinding.ExecuteBindingAsync(null, httpActionContext, (new CancellationTokenSource()).Token).Wait();

    //Assert here
    //httpActionContext.ActionArguments[parameterName] contains the CustomerId
}

Note: If you don't want to create a CustomerId class, you can annotate your parameter with a custom ParameterBindingAttribute. Like so

public void Post([CustomerId] string customerId, Customer customer)

See here on how to create a ParameterBindingAttribute

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