What WebApplicationFactory Gives You
WebApplicationFactory<TEntryPoint> boots your ASP.NET Core application in-memory using TestServer, running the real Program/Startup configuration — routing, middleware, filters, dependency injection — without binding to a real TCP port. You get an HttpClient via factory.CreateClient() that sends requests through the actual pipeline, so integration tests catch problems unit tests can't, such as misconfigured routes, missing middleware ordering, or serialization mismatches between your DTOs and the wire format.
Cricket analogy: Booting the full app via TestServer is like playing a full net session on the actual stadium pitch at the MCG rather than a practice ground, so you catch pitch-specific bounce and swing that a corner net can't reveal.
Overriding Services for Test Isolation
Because integration tests still touch a database, you typically override the real DbContext registration with an in-memory or SQLite-in-memory provider inside WithWebHostBuilder(builder => builder.ConfigureServices(...)), removing the production ServiceDescriptor for DbContextOptions and re-adding a test-friendly one. This keeps tests fast and repeatable while still exercising real EF Core query translation, unlike a fully mocked repository.
Cricket analogy: Swapping the production database for an in-memory provider during tests is like practicing on a synthetic indoor pitch instead of the actual Eden Gardens surface — close enough to rehearse technique, but not identical to match-day conditions.
public class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
if (descriptor != null) services.Remove(descriptor);
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("TestDb"));
});
}
}
public class OrdersApiTests : IClassFixture<CustomWebApplicationFactory>
{
private readonly HttpClient _client;
public OrdersApiTests(CustomWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task GetOrders_ReturnsSuccessAndJson()
{
var response = await _client.GetAsync("/api/orders");
response.EnsureSuccessStatusCode();
Assert.Equal("application/json; charset=utf-8",
response.Content.Headers.ContentType?.ToString());
}
}Testing Authentication and Authorization
For endpoints protected by [Authorize], integration tests commonly register a fake authentication handler (implementing AuthenticationHandler<AuthenticationSchemeOptions>) so requests carry a predictable test identity and claims without needing a real JWT issuer or identity provider. This lets you verify that a 401 is returned for anonymous requests and a 200 is returned once the fake scheme supplies a valid principal, confirming your authorization policies are wired correctly.
Cricket analogy: A fake authentication handler supplying a test identity is like a friendly practice match where the umpire pre-confirms a batsman's identity so the team can focus on testing batting strategy rather than re-verifying credentials every ball.
A fake authentication handler is registered with services.AddAuthentication("Test").AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => {}), then set as the default scheme only inside the test factory's ConfigureServices — production code and its real authentication configuration remain untouched.
Managing Test Data and Cleanup
Each test class typically implements IClassFixture<CustomWebApplicationFactory> so the factory (and its in-memory server) is shared across tests in a class for speed, while individual tests seed and reset data — often re-creating the in-memory database or wrapping operations in a transaction that's rolled back — to avoid one test's leftover data leaking into and breaking another test's assertions.
Cricket analogy: Sharing one WebApplicationFactory across a test class like IClassFixture is like a team sharing one prepared net pitch across a training session, but each batsman resets their own stance and guard before their turn to avoid interference from the last player's marks.
In-memory database providers don't enforce the same constraints as a real relational database — for example, they may not catch a missing foreign key or a unique-index violation. For tests that specifically validate database-level constraints, use the SQLite in-memory provider or a real containerized database via Testcontainers instead.
- WebApplicationFactory boots the real app in-memory via TestServer
- Override service registrations with WithWebHostBuilder to swap in test-friendly implementations
- Register a fake authentication scheme to test [Authorize] endpoints
- Share a factory across a test class with IClassFixture for speed
- Seed and clean up data per test to avoid cross-test contamination
- Integration tests catch pipeline-level bugs unit tests can't see
- Consider SQLite in-memory or Testcontainers when relational constraints matter
Practice what you learned
1. What does WebApplicationFactory<TEntryPoint> use internally to run the application without a real network port?
2. How do you override a production service registration like a DbContext in an integration test?
3. Why implement IClassFixture<CustomWebApplicationFactory> on a test class?
4. What's a key limitation of using an in-memory EF Core provider for integration tests?
Was this page helpful?
You May Also Like
Unit Testing Controllers and Services
Learn how to isolate ASP.NET Core controllers and services with xUnit and Moq to verify business logic without running the full HTTP pipeline.
Logging and Observability with Serilog
Configure structured logging with Serilog and pair it with metrics and distributed tracing to build real observability into an ASP.NET Core API.
ASP.NET Core Interview Questions
A focused review of the ASP.NET Core fundamentals, common pitfalls, and system-design questions that come up most often in technical interviews.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics