Mocking HttpRequest Body Content When Testing Azure Function HTTP Trigger Functions

When creating Azure Functions that are triggered by an HTTP request, you may want to write unit tests for the function Run method. These unit tests can be executed outside of the Azure Functions runtime, just like testing regular methods.

If your HTTP-triggered function takes as the function input an HttpRequest (as opposed to an automatically JSON-deserialized class) you may need to provide request data in your test.

As an example, consider the following code snippet that defines an HTTP-triggered function.

[FunctionName("Portfolio")]
[return: Queue("deposit-requests")]
public static async Task<DepositRequest> Run(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = "portfolio/{investorId}")]HttpRequest req,
    [Table("Portfolio", InvestorType.Individual, "{investorId}")] Investor investor,
    string investorId,
    ILogger log)
{
    log.LogInformation($"C# HTTP trigger function processed a request.");

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

    log.LogInformation($"Request body: {requestBody}");

    var deposit = JsonConvert.DeserializeObject<Deposit>(requestBody);

    // etc.
}

If the  the preceding code is executed in a test, some content needs to be provided to be used when accessing req.Body. To do this using Moq a mock HttpRequest can be created that returns a specified Stream instance for req.Body.

If you want to create a request body that contains a JSON payload, you can use the following helper method in your tests:

private static Mock<HttpRequest> CreateMockRequest(object body)
{            
    var ms = new MemoryStream();
    var sw = new StreamWriter(ms);

    var json = JsonConvert.SerializeObject(body);

    sw.Write(json);
    sw.Flush();

    ms.Position = 0;

    var mockRequest = new Mock<HttpRequest>();
    mockRequest.Setup(x => x.Body).Returns(ms);

    return mockRequest;
}

As an example of using this method in a test:

[Fact]
public async Task ReturnCorrectDepositInformation()
{
    var deposit = new Deposit { Amount = 42 };
    var investor = new Investor { };

    Mock<HttpRequest> mockRequest = CreateMockRequest(deposit);

    DepositRequest result = await Portfolio.Run(mockRequest.Object, investor, "42", new Mock<ILogger>().Object);

    Assert.Equal(42, result.Amount);
    Assert.Same(investor, result.Investor);
}

When the preceding test is run, the function run method will get the contents of the memory stream that contains the JSON.

To learn more about using Moq to create/configure/use mock objects check out my Mocking in .NET Core Unit Tests with Moq: Getting Started Pluralsight course. or to learn more about MemoryStream and how to work with streams in C# check out my Working with Files and Streams course.

You can start watching with a Pluralsight free trial.

SHARE:

Comments (8) -

  • Shivani

    5/1/2019 3:50:41 AM | Reply

    How can I mock the query string parameter if the url is as below
    http://localhost:4300/api/getroles/?enterpriseId="xyz"

    • Luke

      5/8/2019 2:56:10 PM | Reply

      it would look something like:
      mock.Setup(m => m.Query[It.IsAny<string>()].Returns(<the object you are asserting against>);

  • Hasan

    10/1/2019 4:58:14 AM | Reply

    We can pass query to Mock Request but what if we want to pass header, which have custom header and bearer token.
    var request = Mock.Of<HttpRequestMessage>();
    var postParam = new Dictionary<string, StringValues>();
    postParam.Add("param1", "123");            
    request.Query = new QueryCollection(postParam);
    Query part working
    But following header is not and any idea for bearer token
    request.Headers.Add("Transaction", "1234");

  • Vignesh

    2/10/2020 12:39:21 PM | Reply

    Thank you so much. Was looking for this for a long time.

    • Jason Roberts

      2/12/2020 12:20:05 AM | Reply

      No problem Vignesh - glad it was helpful to you Smile

  • Robert

    5/21/2020 2:56:00 PM | Reply

    Can you not use a DefaultHttpContext and populate the request and response objects as desired?

  • Ravi

    9/3/2020 5:53:08 PM | Reply

    Does this code even work? System.NotSupportedException: 'Type to mock must be an interface, a delegate, or a non-sealed, non-static class.'
    HttpRequest is a sealed class

  • vidhya

    1/21/2021 4:07:51 PM | Reply

    How to write such helper method for HttpRequestMessage?  I'm getting error and not able to do so..  It will be very helpful  if you give any idea on that.

    Thanks in Advance !!

Add comment

Loading