4 min read
Integration Testing with WebApplicationFactory
Mind Map Summary
- WebApplicationFactory
- Definition: A testing utility in ASP.NET Core that creates an in-memory test server for your application, enabling full-stack tests without real hosting.
- Key Concepts
WebApplicationFactory<TEntryPoint>: The bootstrap class for the in-memory host.- In-memory Test Server: The app runs within the test process, allowing component interaction.
HttpClient: Standard client used to “talk” to the in-memory server.- Dependency Overrides: Recompiling the DI container for tests (e.g., swapping a real DB for SQLite in-memory).
- Benefits and Challenges
- Pros: High fidelity (tests middleware, routing, DB), increased confidence, and significantly faster than full E2E/browser tests.
- Cons: Slower than unit tests, more complex state management (seeding data), and more resource-intensive.
Core Concepts
Integration testing with WebApplicationFactory is the “gold standard” for testing web APIs. Instead of mocking every service, you spin up the entire application in memory. You send a real HTTP request and receive a real response, verifying that the entire pipe—from middleware to data access—is working as intended.
This approach verifies the interactions between multiple components, ensuring that a change in a service doesn’t break a controller’s contract or that an authorization policy is correctly applied to a route.
Practice Exercise
Using WebApplicationFactory, write an integration test for an API endpoint. The test should:
- Create an in-memory test server for an ASP.NET Core application.
- Make an HTTP GET request to
/api/products. - Assert that the response has a
200 OKstatus code and contains products.
Answer (Integration Test Implementation in C#)
1. The Controller to Test
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static readonly List<Product> _products = new()
{
new Product { Id = 1, Name = "Laptop", Price = 1200 },
new Product { Id = 2, Name = "Mouse", Price = 25 }
};
[HttpGet]
public IActionResult Get() => Ok(_products);
}
2. Custom WebApplicationFactory
This factory allows you to customize the test environment (e.g., using a test database).
public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Optional: Replace production DB with In-Memory DB for faster tests
// services.AddDbContext<AppDbContext>(o => o.UseInMemoryDatabase("TestDb"));
});
}
}
3. The Integration Test (xUnit)
public class ProductsApiTests : IClassFixture<CustomWebApplicationFactory>
{
private readonly HttpClient _client;
public ProductsApiTests(CustomWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetProducts_ReturnsOkAndData()
{
// Act
var response = await _client.GetAsync("/api/products");
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var content = await response.Content.ReadAsStringAsync();
var products = JsonConvert.DeserializeObject<List<Product>>(content);
Assert.NotNull(products);
Assert.Equal(2, products.Count);
Assert.Contains(products, p => p.Name == "Laptop");
}
}
Key Takeaways
IClassFixture: This xUnit interface ensures the test host is shared across all tests in the class, making the test suite much faster.factory.CreateClient(): This isn’t just a regularHttpClient; it’s pre-configured to handle the URI routing for the in-memory server and can even handle cookies/auth automatically.Newtonsoft.Json: Used here to deserialize the response. In modern .NET, you might preferSystem.Text.Jsonfor even better performance.- End-to-End feel, Unit Test speed: This style of testing is far more reliable than pure unit testing for web APIs, as it catches configuration issues that mocks would hide.