Unit test WebApi2 Header Transfer

I am working on a project using WebApi2. In my test project, I use Moq and XUnit.

So far, api testing has been pretty straightforward to make 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 get to something complicated when I need to access the value from the request header.

I created my own Ok () result by extending IHttpActionResult

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

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

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

How am I going to configure Moq using a dummy query?

I spent the last hour or so hunting for an example that allows me to do this using webapi, but I can't find anything.

So far ..... and I'm sure this is 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, }; 

I'm not quite sure what I need to do, since I did not need to customize the HttpRequestBase layout in the past.

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

Thank!!!

+2
asp.net-web-api moq xunit asp.net-web-api2
Jan 16 '14 at 3:23
source share
1 answer

I believe that you should avoid reading the headers in your controller for a better separation of problems (you do not need to read the client correctly from the request body in the controller?) And testability.

How do I do this, create a class CustomerId (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 ClientIdParameterBinding

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

Then in my controller

 public void Post(CustomerId id, Customer customer) 

Parameter Binding Testing

 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 do not want to create the CustomerId class, you can annotate your parameter with a custom ParameterBindingAttribute . In this way

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

See here how to create a ParameterBindingAttribute parameter.

+6
Jan 16 '14 at 4:37
source share



All Articles