Integration Test কী?
Real HTTP request → Controller → Service → DB — পুরো pipeline test। Bug catch করে যা unit test missed।
Setup
dotnet add package Microsoft.AspNetCore.Mvc.Testing dotnet add package Microsoft.EntityFrameworkCore.InMemory
WebApplicationFactory
public class CustomWebAppFactory : WebApplicationFactory<Program> {
protected override void ConfigureWebHost(IWebHostBuilder builder) {
builder.ConfigureServices(services => {
// Real DbContext remove
var desc = services.SingleOrDefault(d =>
d.ServiceType == typeof(DbContextOptions<AppDbContext>));
if (desc != null) services.Remove(desc);
// In-memory DB add
services.AddDbContext<AppDbContext>(opt =>
opt.UseInMemoryDatabase("IntegrationTestDb"));
// Seed data
using var scope = services.BuildServiceProvider().CreateScope();
var ctx = scope.ServiceProvider.GetRequiredService<AppDbContext>();
ctx.Database.EnsureCreated();
ctx.Products.Add(new Product { Id = 1, Name = "Test", Price = 100 });
ctx.SaveChanges();
});
}
}
API Test
public class ProductsApiTests : IClassFixture<CustomWebAppFactory> {
private readonly HttpClient _client;
public ProductsApiTests(CustomWebAppFactory factory) {
_client = factory.CreateClient();
}
[Fact]
public async Task GetAll_Returns200() {
var response = await _client.GetAsync("/api/products");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var products = JsonSerializer.Deserialize<List<ProductDto>>(json,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
products.Should().NotBeEmpty();
}
[Fact]
public async Task Post_CreatesProduct() {
var dto = new { Name = "New", Price = 500 };
var response = await _client.PostAsJsonAsync("/api/products", dto);
response.StatusCode.Should().Be(HttpStatusCode.Created);
}
[Fact]
public async Task Get_NotExists_Returns404() {
var response = await _client.GetAsync("/api/products/9999");
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
}
}
Authenticated Test
// Custom AuthHandler দিয়ে fake auth
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
var claims = new[] { new Claim(ClaimTypes.Name, "TestUser") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
return Task.FromResult(AuthenticateResult.Success(ticket));
}
}
// Factory ConfigureServices-এ
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", null);
// Test
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
Testcontainers (Real DB in Docker)
dotnet add package Testcontainers.MsSql
var container = new MsSqlBuilder().WithPassword("Yourpass!").Build();
await container.StartAsync();
var connStr = container.GetConnectionString();
// real SQL Server in container — production-like test