AzureFunctions.IntegrationTests
1.0.1
dotnet add package AzureFunctions.IntegrationTests --version 1.0.1
NuGet\Install-Package AzureFunctions.IntegrationTests -Version 1.0.1
<PackageReference Include="AzureFunctions.IntegrationTests" Version="1.0.1" />
<PackageVersion Include="AzureFunctions.IntegrationTests" Version="1.0.1" />
<PackageReference Include="AzureFunctions.IntegrationTests" />
paket add AzureFunctions.IntegrationTests --version 1.0.1
#r "nuget: AzureFunctions.IntegrationTests, 1.0.1"
#:package AzureFunctions.IntegrationTests@1.0.1
#addin nuget:?package=AzureFunctions.IntegrationTests&version=1.0.1
#tool nuget:?package=AzureFunctions.IntegrationTests&version=1.0.1
AzureFunctions.IntegrationTests
A testing library for Azure Functions v4 (isolated worker process model) that provides a FunctionAppFactory similar to WebApplicationFactory in ASP.NET Core. This makes it easy to write integration tests for your Azure Functions without needing to start the actual Functions runtime.
Features
- ๐ Easy to use - Similar API to
WebApplicationFactory<T>that developers already know - ๐ Auto-discovery - Automatically finds and invokes your Azure Functions
- ๐งช In-memory testing - No need to start the Functions host or use HTTP
- ๐ฏ Full dependency injection - Access to the service provider for testing
- ๐ Route parameter support - Handles complex routes with parameters like
{id},{email}, etc. - โ๏ธ Customizable - Virtual methods to override host configuration
- ๐ HttpClient integration - Use familiar HttpClient for testing
Installation
dotnet add package AzureFunctions.IntegrationTests
Quick Start
0. Modify Your Program.cs for Testability
First, expose the host creation logic in your Azure Functions project, add public partial class Program and expose the GetHost function
var host= GetHost(args);
host.Run();
public partial class Program {
public static IHost GetHost(string[] args)
{
var builder = FunctionsApplication.CreateBuilder(args);
builder.ConfigureFunctionsWebApplication();
builder.Services
.AddApplicationInsightsTelemetryWorkerService()
.ConfigureFunctionsApplicationInsights();
return builder.Build();
}
}
1. Basic Usage
using AzureFunctions.IntegrationTests;
using Xunit;
public class MyFunctionTests : IClassFixture<FunctionAppFactory<Program>>
{
private readonly HttpClient _client;
public MyFunctionTests(FunctionAppFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetUser_ReturnsOk()
{
// Act
var response = await _client.GetAsync("/api/users/123");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
2. Accessing Services
public class MyFunctionTests : IClassFixture<FunctionAppFactory<Program>>
{
private readonly FunctionAppFactory<Program> _factory;
public MyFunctionTests(FunctionAppFactory<Program> factory)
{
_factory = factory;
}
[Fact]
public void CanAccessServices()
{
// Arrange
using var scope = _factory.Services.CreateScope();
var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
// Act & Assert
Assert.NotNull(myService);
}
}
3. Custom Headers
[Fact]
public async Task PostUser_WithCustomHeaders_ReturnsCreated()
{
// Arrange
var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "test-tenant");
var content = new StringContent(
JsonSerializer.Serialize(new { name = "John" }),
Encoding.UTF8,
"application/json");
// Act
var response = await client.PostAsync("/api/users", content);
// Assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}
Advanced Usage
Custom Factory for Test Configuration
You can create a custom factory to override services or configuration:
public class CustomFunctionAppFactory : FunctionAppFactory<Program>
{
protected override void ConfigureHostBuilder(IHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Replace a service with a mock
services.AddScoped<IMyService, MockMyService>();
// Add test-specific services
services.AddSingleton<ITestDataSeeder, TestDataSeeder>();
});
builder.ConfigureAppConfiguration((context, config) =>
{
// Add test-specific configuration
config.AddInMemoryCollection(new Dictionary<string, string>
{
["ConnectionStrings:TestDb"] = "test-connection-string"
});
});
}
protected override void ConfigureEnvironment()
{
base.ConfigureEnvironment();
// Set additional environment variables for testing
Environment.SetEnvironmentVariable("TEST_MODE", "true");
}
}
// Usage
public class MyTests : IClassFixture<CustomFunctionAppFactory>
{
private readonly HttpClient _client;
public MyTests(CustomFunctionAppFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task Test_WithMockedServices()
{
// Your test implementation
}
}
Integration with xUnit Collection Fixtures
For sharing the factory across multiple test classes:
[CollectionDefinition("Function Collection")]
public class FunctionCollection : ICollectionFixture<FunctionAppFactory<Program>>
{
// This class has no code, it's just a marker for xUnit
}
[Collection("Function Collection")]
public class UserTests
{
private readonly HttpClient _client;
public UserTests(FunctionAppFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetUser_ReturnsOk()
{
var response = await _client.GetAsync("/api/users/123");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
[Collection("Function Collection")]
public class ProductTests
{
private readonly HttpClient _client;
public ProductTests(FunctionAppFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetProduct_ReturnsOk()
{
var response = await _client.GetAsync("/api/products/456");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
Testing Route Parameters
The library automatically handles route parameters:
// Given an Azure Function with route: "users/{userId}/orders/{orderId}"
[Function("GetOrder")]
public IActionResult GetOrder(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "users/{userId}/orders/{orderId}")]
HttpRequestData req,
Guid userId,
int orderId)
{
// Function implementation
}
// Test
[Fact]
public async Task GetOrder_WithRouteParameters_ReturnsOk()
{
var response = await _client.GetAsync(
"/api/users/550e8400-e29b-41d4-a716-446655440000/orders/123");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
How It Works
- Auto-Discovery: The factory scans your entry point assembly for Azure Functions (methods decorated with
[Function]attribute) - Host Creation: It discovers your
GetHost()orCreateHostBuilder()method and creates the host - Request Routing: When you make an HTTP request via the test client, it routes to the appropriate function
- Parameter Binding: Route parameters are automatically extracted and converted to the correct types
- Response Conversion:
IActionResultresponses are converted toHttpResponseMessagefor easy assertion
Requirements
- .NET 8.0 or later
- Azure Functions v4 (isolated worker process model)
- Your Azure Functions project must have a
Programclass with either:public static IHost GetHost(string[] args)method, orpublic static IHostBuilder CreateHostBuilder(string[] args)method
Supported Features
- โ HTTP triggers (GET, POST, PUT, DELETE, PATCH, etc.)
- โ Route parameters (string, int, Guid, DateTime, enum, and nullable types)
- โ Query string parameters
- โ Request headers
- โ Request body
- โ IActionResult responses (OkObjectResult, NotFoundResult, BadRequestResult, etc.)
- โ Dependency injection
- โ Custom configuration
- โ Environment variables
Limitations
- Only supports HTTP-triggered functions
- Timer, Queue, Blob, and other trigger types are not supported
- Does not test the actual HTTP binding (e.g., authentication middleware at the HTTP level)
Example Project Structure
MyAzureFunctionsApp/
โโโ src/
โ โโโ MyApp.API/ # Your Azure Functions project
โ โ โโโ Functions/
โ โ โ โโโ UserFunctions.cs
โ โ โ โโโ ProductFunctions.cs
โ โ โโโ Program.cs
โ โโโ MyApp.Core/ # Your business logic
โ โโโ Services/
โ โโโ UserService.cs
โโโ tests/
โโโ MyApp.IntegrationTests/
โโโ UserFunctionsTests.cs
โโโ ProductFunctionsTests.cs
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Inspired by ASP.NET Core's WebApplicationFactory<TEntryPoint> pattern for testing.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Mvc.Core (>= 2.2.5)
- Microsoft.Azure.Functions.Worker (>= 2.0.0)
- Microsoft.Azure.Functions.Worker.Extensions.Http (>= 3.0.12)
- Microsoft.Extensions.Hosting (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.