单元测试WebApi2传球头球值 [英] Unit test WebApi2 passing header values

查看:273
本文介绍了单元测试WebApi2传球头球值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作使用WebApi2的项目。随着我的测试项目中,我使用起订量和的xUnit。

I am working on a project using WebApi2. With my test project I am using Moq and XUnit.

到目前为止测试的API已经被pretty直截了当地不喜欢

So far testing an api has been pretty straight forward to do a GET like

  [Fact()]
    public void GetCustomer()
    {
        var id = 2;

        _customerMock.Setup(c => c.FindSingle(id))
            .Returns(FakeCustomers()
            .Single(cust => cust.Id == id));

        var result = new CustomersController(_customerMock.Object).Get(id);

        var negotiatedResult = result as OkContentActionResult<Customer>;
        Assert.NotNull(negotiatedResult);
        Assert.IsType<OkNegotiatedContentResult<Customer>>(negotiatedResult);
        Assert.Equal(negotiatedResult.Content.Id,id);
    }

现在我移动到的东西有点复杂,我需要从请求头获取价值。

Now I am moving onto something a little complicated where I need to access value from the request header.

我已经通过扩展IHttpActionResult创建了自己的好()结果

I have created my own Ok() result by extending the IHttpActionResult

   public OkContentActionResult(T content,HttpRequestMessage request)
    {
        _request = request;
        _content = content;
    }

这让我有一个小帮手读取请求的头值。

This allows me to have a small helper that reads the header value from the request.

 public virtual IHttpActionResult Post(Customer customer)
    {
        var header = RequestHeader.GetHeaderValue("customerId", this.Request);

        if (header != "1234")

我怎么打算设置起订量与虚拟请求?

How am I meant to setup Moq with a dummy Request?

我已经花了一小时左右狩猎,让我做这件事与不过的WebAPI我不能似乎发现了什么的例子。

I have spent the last hour or so hunting for an example that allows me to do this with webapi however I cant seem to find anything.

到目前为止.....我很pretty确保其错误的API,但我有

So far.....and I am pretty sure its wrong for the api but I have

      // arrange
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var headers = new NameValueCollection
        {
            { "customerId", "111111" }
        };
        request.Setup(x => x.Headers).Returns(headers);
        request.Setup(x => x.HttpMethod).Returns("GET");
        request.Setup(x => x.Url).Returns(new Uri("http://foo.com"));
        request.Setup(x => x.RawUrl).Returns("/foo");
        context.Setup(x => x.Request).Returns(request.Object);
        var controller = new Mock<ControllerBase>();
        _customerController = new CustomerController()
        {
            //  Request = request,

        };

我真的不知道接下来我需要什么,因为我还没有需要,在过去建立一个模拟的Htt prequestBase做的。

I am not really sure what next I need to do as I havent needed to setup a mock HttpRequestBase in the past.

任何人都可以提出一个很好的文章或点我在正确的方向?

Can anyone suggest a good article or point me in the right direction?

感谢您!

推荐答案

我认为,你应该避免在读你的控制器头为更好的关注分离(你不需要读取请求主体客户控制器对不对?)和可测试性。

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.

我将如何做到这一点是创建一个客户ID 类(这是可选的。见下面的注释)和 CustomerIdParameterBinding

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

编写了CustomerIdParameterBinding

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)

测试参数绑定

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
}

注意:如果你不想创建一个客户ID 类,可以用自定义 ParameterBindingAttribute 。像这样

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)

<一个href=\"http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api\">See这里就如何创建一个ParameterBindingAttribute

这篇关于单元测试WebApi2传球头球值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆