Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying the content of a HttpRequestMessage for a Web API unit test

I have a web API controller method I want to unit test. It takes in a HttpRequestMessage but I can't work out how to set the content that I want to pass in. Is it possible to create/mock the HttpRequestMessage so that I can give it a string that I want to be the result of await request.Content.ReadAsStringAsync()?

This is my controller method:

[HttpPost]
public async Task<HttpResponseMessage> Post(HttpRequestMessage request)
{
    var data = await request.Content.ReadAsStringAsync();
    //do something with data
}

I can easily create the HttpRequestMessage with its parameterless constructor, but I can't work out how to set the content to a meaningful value. I would like my test to work along these lines:

[TestMethod]
public async Task PostMethodWorks()
{
    var controller = new MyController();

    var data = "this will be JSON";
    var httpRequestMessage = new HttpRequestMessage();
    //set the content somehow so that httpRequestMessage.Content.ReadAsStringAsync returns data

    var response = await controller.Post(httpRequestMessage);

    //assert something about the response here
}

Is it possible to set the value of the content to some JSON, or will I need to change the method so it takes in a different parameter?

(For more context, the reason I want to have the method taking in a HttpRequestMessage is because I'm working on a legacy codebase with that has loads of controller methods which take in a HttpRequestMessage.)

like image 502
Tim Avatar asked Sep 13 '18 16:09

Tim


People also ask

What is HttpRequestMessage C#?

HttpRequestMessage(HttpMethod, String) Initializes a new instance of the HttpRequestMessage class with an HTTP method and a request Uri. HttpRequestMessage(HttpMethod, Uri) Initializes a new instance of the HttpRequestMessage class with an HTTP method and a request Uri.


1 Answers

Is it possible to set the value of the content to some JSON

Yes

You can use any one of the many HttpContent derived classes. Since in this case you want to send JSON content, you would want to use StringContent class

For example

[TestMethod]
public async Task PostMethodWorks() {
    //Arrange
    var controller = new MyController();

    var data = "this will be JSON";
    var httpRequestMessage = new HttpRequestMessage();

    //set the content somehow so that httpRequestMessage.Content.ReadAsStringAsync returns data 
    httpRequestMessage.Content = new StringContent(data, Encoding.UTF8, "application/json");


    //Act
    var response = await controller.Post(httpRequestMessage);

    //Assert
    //assert something about the response here
}

This however feels like an XY problem as ideally Web API actions don't take HttpRequestMessage as a argument.

or will I need to change the method so it takes in a different parameter?

Model binders exist that can be used to have strongly typed action parameters that will parse the incoming data and populate the models before passing then to the actions.

like image 71
Nkosi Avatar answered Oct 03 '22 20:10

Nkosi