
While working on a project recently, I needed an approach for creating some functional tests for a few HTTP-triggered Azure Functions I was working on. Typically I would use WebApplicationFactory
for testing a .NET web application, but this doesn't seem to be available for isolated Azure Functions. I saw a post that mentioned UnitTestEx might offer a way forward and decided to give it a try!
Package | Version |
---|---|
.NET | 8 |
UnitTestEx | 5.3.0 |
UnitTestEx.Azure.Functions | 5.3.0 |
UnitTestEx.Xunit | 5.3.0 |
Shouldly | 4.3.0 |
xunit | 2.9.3 |
This is a straightforward HTTP-triggered Azure function that I've put together which doubles a given number. It takes a request in the format defined by DoubleMyNumberRequest
. The request body is deserialized into an object of this type. If the body is not present, then the caller will receive a 400 Bad Request
result, but if the request is successfully decoded then the caller will receive a 200 OK
response with the doubled number in the response body.
namespace FunctionalTestingExample;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
public class DoubleMyNumberFunction(ILogger<DoubleMyNumberFunction> logger)
{
[Function(nameof(DoubleMyNumberFunction))]
public async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "double-my-number")] HttpRequest req)
{
logger.LogInformation("Received a request to double a number...");
var request = await req.ReadFromJsonAsync<DoubleMyNumberRequest>();
if (request == null)
{
return new BadRequestObjectResult("A request object must be supplied");
}
return new OkObjectResult(request.Number * 2);
}
}
public record DoubleMyNumberRequest(double Number);
I'm an XUnit fan, so that's what I've used in this example. This is a test fixture which uses XUnit's InlineData
feature to supply several different test cases to a single test. See this excellent guide here on creating parameterised tests in XUnit.
Use FunctionTester.Create<T>
to create an instance of the function tester. Then, configure that tester to point at your function under test, in our case DoubleMyNumberFunction
.
Then, create an HTTP request using the function tester, supplying the HTTP method, API route, body and content type. Execute the request, and then assert the results!
This is a simple example and you may wish to extract / generalise / simplify this for use across several different tests.
namespace FunctionalTestingExample.Tests;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Shouldly;
using UnitTestEx;
using UnitTestEx.Azure.Functions;
using UnitTestEx.Xunit;
using Xunit.Abstractions;
public class WhenDoublingANumber(ITestOutputHelper helper) : UnitTestBase(helper)
{
[Theory]
[InlineData(0, 0)]
[InlineData(-2, -4)]
[InlineData(3.5, 7)]
public async Task ShouldDoubleTheNumberAsync(double number, int expectedResult)
{
using var functionTester = FunctionTester.Create<Program>();
var triggerTester = functionTester
.HttpTrigger<DoubleMyNumberFunction>()
.WithRouteCheck(RouteCheckOption.None);
var requestBody = new DoubleMyNumberRequest(number);
var request = functionTester.CreateHttpRequest(HttpMethod.Post, "api/double-my-number", JsonSerializer.Serialize(requestBody), "application/json");
var response = await triggerTester.RunAsync(f => f.RunAsync(request));
response.Result.ShouldBeOfType<OkObjectResult>();
var responseBody = ((OkObjectResult)response.Result).Value as double?;
responseBody.ShouldNotBeNull();
responseBody.Value.ShouldBe(expectedResult);
}
}
Check out a full example in this repository.