[{"data":1,"prerenderedAt":106},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Ftesting\u002Fintegration-testing":3},{"page":4,"siblings":94,"blog":103},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fdotnet\u002Ftesting\u002Fintegration-testing.md","Integration Testing",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"hard","md",".NET Core","dotnet",{},true,3,"\u002Fdotnet\u002Ftesting\u002Fintegration-testing",[23,28,33,37,41,45,49,53,57,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"integration-vs-unit","easy","What is the difference between unit testing and integration testing in .NET?","**Unit tests** verify a single class in isolation with all dependencies mocked.\n**Integration tests** verify that multiple components work correctly together —\nincluding real databases, HTTP pipelines, and middleware.\n\n```csharp\n\u002F\u002F Unit test — PricingEngine in complete isolation:\n[Fact]\npublic void Calculate_AppliesDiscountCorrectly()\n{\n    var engine = new PricingEngine(); \u002F\u002F no dependencies\n    var result = engine.Calculate(100m, discountPct: 10);\n    Assert.Equal(90m, result);\n}\n\n\u002F\u002F Integration test — full HTTP pipeline with real EF Core (in-memory):\npublic class OrdersIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly HttpClient _client;\n\n    public OrdersIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task PostOrder_ReturnsCreated_AndPersistsToDatabase()\n    {\n        var payload = new StringContent(\n            \"\"\"{\"sku\":\"X\",\"quantity\":2}\"\"\",\n            Encoding.UTF8, \"application\u002Fjson\");\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n        \u002F\u002F Verify via GET that it actually persisted:\n        var location = response.Headers.Location!;\n        var getResp  = await _client.GetAsync(location);\n        getResp.EnsureSuccessStatusCode();\n    }\n}\n```\n\nIntegration tests are slower and harder to parallelize than unit tests but catch\na different class of bugs: mismatched serialization, middleware ordering problems,\nEF Core mapping errors, and misconfigured DI.\n\n**Rule of thumb:** Test business logic with unit tests; test cross-layer concerns\n(HTTP → service → DB round-trips) with integration tests. Aim for many unit tests\nand a smaller number of high-value integration tests.\n",{"id":29,"difficulty":30,"q":31,"a":32},"webapplicationfactory","medium","What is WebApplicationFactory and how do you use it to test ASP.NET Core endpoints?","`WebApplicationFactory\u003CTProgram>` (from `Microsoft.AspNetCore.Mvc.Testing`)\nspins up an in-process test server that runs the real ASP.NET Core pipeline.\nTests call it through an `HttpClient` with no networking overhead.\n\n```csharp\n\u002F\u002F Install: dotnet add package Microsoft.AspNetCore.Mvc.Testing\n\n\u002F\u002F Minimal setup — use the app as-is:\npublic class BasicIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly HttpClient _client;\n\n    public BasicIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task GetHealth_Returns200()\n    {\n        var response = await _client.GetAsync(\"\u002Fhealth\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n\n\u002F\u002F Custom factory — override configuration or swap services:\npublic class CustomWebFactory : WebApplicationFactory\u003CProgram>\n{\n    protected override void ConfigureWebHost(IWebHostBuilder builder)\n    {\n        builder.ConfigureServices(services =>\n        {\n            \u002F\u002F Replace the real DbContext with an in-memory one:\n            var descriptor = services.SingleOrDefault(\n                d => d.ServiceType == typeof(DbContextOptions\u003CAppDbContext>));\n            if (descriptor != null)\n                services.Remove(descriptor);\n\n            services.AddDbContext\u003CAppDbContext>(opts =>\n                opts.UseInMemoryDatabase(\"TestDb-\" + Guid.NewGuid()));\n\n            \u002F\u002F Swap a real external service with a fake:\n            services.AddSingleton\u003CIEmailSender, FakeEmailSender>();\n        });\n\n        builder.UseEnvironment(\"Testing\");\n    }\n}\n\n\u002F\u002F Use the custom factory:\npublic class OrderTests : IClassFixture\u003CCustomWebFactory>\n{\n    private readonly HttpClient _client;\n    public OrderTests(CustomWebFactory factory) => _client = factory.CreateClient();\n}\n```\n\n**Rule of thumb:** Use `IClassFixture\u003CWebApplicationFactory\u003CProgram>>` for\nread-only tests (the factory is shared). When tests write data, use a unique\nin-memory database per class to prevent interference between test runs.\n",{"id":34,"difficulty":30,"q":35,"a":36},"inmemory-vs-sqlite-testing","Should you use the EF Core in-memory provider or SQLite for integration tests?","The **in-memory provider** is fast but doesn't enforce relational constraints\n(FK, unique indexes) and behaves differently from real SQL. **SQLite in-memory\nmode** runs real SQL and is fast enough for most test suites.\n\n```csharp\n\u002F\u002F Option 1: EF Core InMemory — fast, but no FK enforcement or raw SQL:\nservices.AddDbContext\u003CAppDbContext>(opts =>\n    opts.UseInMemoryDatabase(\"TestDb\"));\n\n\u002F\u002F Pitfall: this passes with InMemory but would fail in production:\n\u002F\u002F INSERT with a FK violation → InMemory silently succeeds\n\n\u002F\u002F Option 2: SQLite in-memory — real SQL, relational constraints enforced:\n\u002F\u002F dotnet add package Microsoft.EntityFrameworkCore.Sqlite\n\nservices.AddDbContext\u003CAppDbContext>(opts =>\n    opts.UseSqlite(\"Data Source=:memory:\"));\n\n\u002F\u002F SQLite in-memory databases are per-connection.\n\u002F\u002F Keep the connection open for the test's lifetime:\npublic class SqliteTestFixture : IDisposable\n{\n    public SqliteConnection Connection { get; }\n    public AppDbContext    Context    { get; }\n\n    public SqliteTestFixture()\n    {\n        Connection = new SqliteConnection(\"Data Source=:memory:\");\n        Connection.Open();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlite(Connection)\n            .Options;\n\n        Context = new AppDbContext(opts);\n        Context.Database.EnsureCreated(); \u002F\u002F create schema\n    }\n\n    public void Dispose() { Context.Dispose(); Connection.Close(); }\n}\n\n\u002F\u002F Option 3: Respawn + real DB — reset a real database between tests (slowest):\n\u002F\u002F Respawn is a NuGet package that resets SQL Server\u002FPostgres state fast\n\u002F\u002F by deleting rows in dependency order without recreating the schema.\n```\n\n**Rule of thumb:** Use SQLite in-memory for most integration tests — it's fast\nand realistic. Reserve a real database (via Testcontainers or Respawn) for\ntests that exercise database-specific features (full-text search, JSON columns,\nstored procedures).\n",{"id":38,"difficulty":30,"q":39,"a":40},"seeding-test-data","How do you seed test data for integration tests in .NET?","Test data should be created in the test itself (or a fixture) — never rely on\ndata already in the database from a previous test, as that creates order\ndependencies.\n\n```csharp\npublic class ProductTests : IClassFixture\u003CCustomWebFactory>, IAsyncLifetime\n{\n    private readonly HttpClient   _client;\n    private readonly AppDbContext _db;\n\n    public ProductTests(CustomWebFactory factory)\n    {\n        _client = factory.CreateClient();\n        \u002F\u002F Get a scoped DbContext from the test server's DI container:\n        var scope = factory.Services.CreateScope();\n        _db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    }\n\n    public async Task InitializeAsync()\n    {\n        \u002F\u002F Seed deterministic test data before each test:\n        await _db.Database.EnsureCreatedAsync();\n        _db.Products.AddRange(\n            new Product { Id = 1, Name = \"Widget\",  Price = 9.99m },\n            new Product { Id = 2, Name = \"Gadget\",  Price = 24.99m }\n        );\n        await _db.SaveChangesAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        \u002F\u002F Clean up so the next test class starts from a known state:\n        _db.Products.RemoveRange(_db.Products);\n        await _db.SaveChangesAsync();\n    }\n\n    [Fact]\n    public async Task GetProducts_ReturnsAllSeededProducts()\n    {\n        var response = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n        response.EnsureSuccessStatusCode();\n        var products = await response.Content.ReadFromJsonAsync\u003CList\u003CProduct>>();\n        Assert.Equal(2, products!.Count);\n    }\n}\n```\n\nFor complex seeding, extract an `ObjectMother` or builder so test bodies stay\nfocused on the scenario, not the setup.\n\n**Rule of thumb:** Seed exactly the data each test needs, no more. Use unique\nIDs (or GUIDs) to avoid collisions between tests running in parallel.\n",{"id":42,"difficulty":30,"q":43,"a":44},"testing-authenticated-endpoints","How do you test authenticated ASP.NET Core endpoints in integration tests?","Integration tests need a way to bypass or fake authentication. The standard\napproach is a custom `AuthenticationHandler` that grants a fixed test identity.\n\n```csharp\n\u002F\u002F Custom test auth handler:\npublic class TestAuthHandler : AuthenticationHandler\u003CAuthenticationSchemeOptions>\n{\n    public TestAuthHandler(\n        IOptionsMonitor\u003CAuthenticationSchemeOptions> options,\n        ILoggerFactory logger, UrlEncoder encoder)\n        : base(options, logger, encoder) { }\n\n    protected override Task\u003CAuthenticateResult> HandleAuthenticateAsync()\n    {\n        var claims = new[]\n        {\n            new Claim(ClaimTypes.Name, \"test-user\"),\n            new Claim(ClaimTypes.Role, \"Admin\"),\n            new Claim(\"sub\",           \"user-42\"),\n        };\n        var identity  = new ClaimsIdentity(claims, \"Test\");\n        var principal = new ClaimsPrincipal(identity);\n        var ticket    = new AuthenticationTicket(principal, \"Test\");\n\n        return Task.FromResult(AuthenticateResult.Success(ticket));\n    }\n}\n\n\u002F\u002F Register in the custom WebApplicationFactory:\nprotected override void ConfigureWebHost(IWebHostBuilder builder)\n{\n    builder.ConfigureServices(services =>\n    {\n        services.AddAuthentication(\"Test\")\n                .AddScheme\u003CAuthenticationSchemeOptions, TestAuthHandler>(\"Test\", _ => { });\n    });\n}\n\n\u002F\u002F Now all requests to _client are authenticated as \"test-user\" \u002F \"Admin\":\n[Fact]\npublic async Task AdminEndpoint_AuthenticatedUser_Returns200()\n{\n    var response = await _client.GetAsync(\"\u002Fapi\u002Fadmin\u002Fdashboard\");\n    Assert.Equal(HttpStatusCode.OK, response.StatusCode);\n}\n\n\u002F\u002F Test unauthorized access with a second client that has no auth:\nvar anonClient = _factory.CreateClient(\n    new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });\n\u002F\u002F anonClient requests have no authentication header → 401\n```\n\n**Rule of thumb:** Create one factory for authenticated scenarios and configure\n`CreateClient()` per test when you need to vary the identity (different roles,\ndifferent claims) within the same test class.\n",{"id":46,"difficulty":14,"q":47,"a":48},"testcontainers","What are Testcontainers and when should you use them for .NET integration tests?","**Testcontainers** (`Testcontainers` NuGet) starts real Docker containers\n(SQL Server, Postgres, Redis, etc.) during the test run and tears them down\nafter. This gives you production-equivalent database behavior without\nmaintaining a shared test instance.\n\n```csharp\n\u002F\u002F dotnet add package Testcontainers.MsSql\n\npublic class SqlServerIntegrationTests\n    : IAsyncLifetime, IClassFixture\u003CMsSqlContainer>\n{\n    private readonly MsSqlContainer _sqlContainer =\n        new MsSqlBuilder()\n            .WithImage(\"mcr.microsoft.com\u002Fmssql\u002Fserver:2022-latest\")\n            .WithPassword(\"Str0ng!Passw0rd\")\n            .Build();\n\n    private AppDbContext _db = default!;\n\n    public async Task InitializeAsync()\n    {\n        await _sqlContainer.StartAsync();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlServer(_sqlContainer.GetConnectionString())\n            .Options;\n\n        _db = new AppDbContext(opts);\n        await _db.Database.MigrateAsync(); \u002F\u002F run real EF migrations\n    }\n\n    public async Task DisposeAsync()\n    {\n        await _db.DisposeAsync();\n        await _sqlContainer.DisposeAsync();\n    }\n\n    [Fact]\n    public async Task CreateOrder_PersistsAndRetrievesWithRealConstraints()\n    {\n        var order = new Order { Sku = \"X\", Quantity = 1, CustomerId = Guid.NewGuid() };\n        _db.Orders.Add(order);\n        await _db.SaveChangesAsync();\n\n        var retrieved = await _db.Orders.FindAsync(order.Id);\n        Assert.NotNull(retrieved);\n        Assert.Equal(\"X\", retrieved.Sku);\n    }\n}\n```\n\nTestcontainers requires Docker to be running on the test host. They are slower\nthan in-memory alternatives (~5-15 s startup) but catch database-specific bugs\nthat in-memory databases miss.\n\n**Rule of thumb:** Use Testcontainers for tests that must exercise database-specific\nbehavior (triggers, JSON queries, full-text search, EF migrations). Use\nSQLite in-memory for fast feedback on CRUD logic.\n",{"id":50,"difficulty":30,"q":51,"a":52},"testing-middleware","How do you write integration tests that target a specific middleware component?","Use `WebApplicationFactory` to build a minimal host that includes only the\nmiddleware under test, or use `TestServer` directly for fine-grained control.\n\n```csharp\n\u002F\u002F Testing a custom ExceptionHandlingMiddleware:\npublic class ExceptionMiddlewareTests\n{\n    [Fact]\n    public async Task Middleware_WhenDownstreamThrows_Returns500WithProblemDetails()\n    {\n        \u002F\u002F Build a minimal test host with only the middleware under test:\n        using var host = await new HostBuilder()\n            .ConfigureWebHost(webBuilder =>\n            {\n                webBuilder.UseTestServer();\n                webBuilder.Configure(app =>\n                {\n                    app.UseMiddleware\u003CExceptionHandlingMiddleware>();\n                    \u002F\u002F Next handler always throws:\n                    app.Run(_ => throw new InvalidOperationException(\"Boom!\"));\n                });\n            })\n            .StartAsync();\n\n        var client = host.GetTestClient();\n        var response = await client.GetAsync(\"\u002F\");\n\n        Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);\n        var body = await response.Content.ReadAsStringAsync();\n        Assert.Contains(\"application\u002Fproblem+json\",\n            response.Content.Headers.ContentType!.MediaType);\n    }\n}\n\n\u002F\u002F Testing request\u002Fresponse transformation (e.g. a rate-limiting middleware):\n[Fact]\npublic async Task RateLimiter_After10Requests_Returns429()\n{\n    using var host = await new HostBuilder()\n        .ConfigureWebHost(w =>\n        {\n            w.UseTestServer();\n            w.Configure(app =>\n            {\n                app.UseMiddleware\u003CRateLimitingMiddleware>(maxRequests: 10);\n                app.Run(ctx => ctx.Response.WriteAsync(\"OK\"));\n            });\n        })\n        .StartAsync();\n\n    var client = host.GetTestClient();\n    for (int i = 0; i \u003C 10; i++)\n        (await client.GetAsync(\"\u002F\")).EnsureSuccessStatusCode();\n\n    var eleventh = await client.GetAsync(\"\u002F\");\n    Assert.Equal(HttpStatusCode.TooManyRequests, eleventh.StatusCode);\n}\n```\n\n**Rule of thumb:** Use `TestServer` with a hand-built pipeline to test\nmiddleware in isolation. Use `WebApplicationFactory` to test middleware\nbehavior inside the full application pipeline.\n",{"id":54,"difficulty":30,"q":55,"a":56},"parallel-test-execution","How does xUnit handle parallel test execution and how do integration tests affect it?","xUnit runs tests in different assemblies in parallel by default. Tests within\nthe same class run sequentially; tests in different classes within the same\nassembly run sequentially too (unless opt-in parallelism is enabled).\n\n```csharp\n\u002F\u002F xunit.runner.json — control parallelism settings:\n{\n  \"parallelizeAssembly\": true,\n  \"parallelizeTestCollections\": true,\n  \"maxParallelThreads\": 4\n}\n\n\u002F\u002F Collection attribute — group tests that must NOT run in parallel:\n[Collection(\"Integration\")]  \u002F\u002F same collection name = same test runner thread\npublic class OrderTests      { \u002F* ... *\u002F }\n\n[Collection(\"Integration\")]\npublic class ProductTests    { \u002F* ... *\u002F }\n\n\u002F\u002F ICollectionFixture — share an expensive fixture across a collection:\n[CollectionDefinition(\"Integration\")]\npublic class IntegrationCollection : ICollectionFixture\u003CCustomWebFactory> { }\n\n\u002F\u002F Both test classes share ONE CustomWebFactory instance:\n[Collection(\"Integration\")]\npublic class OrderTests\n{\n    private readonly HttpClient _client;\n    public OrderTests(CustomWebFactory factory) => _client = factory.CreateClient();\n}\n\n\u002F\u002F Isolation strategy when sharing a factory:\n\u002F\u002F Each test uses a unique resource (GUID-named database, distinct SKU, etc.)\n\u002F\u002F so parallel tests within the collection don't step on each other's data.\n```\n\nShared mutable state (a single in-memory database) is the most common cause\nof intermittent failures in integration tests run in parallel.\n\n**Rule of thumb:** Put integration tests that share a database fixture in the\nsame `[Collection]`. Use unique IDs for test data to allow parallel execution\nwithin that collection.\n",{"id":58,"difficulty":30,"q":59,"a":60},"httpclient-typed-client-testing","How do you test a typed HttpClient in ASP.NET Core?","A typed HttpClient wraps `HttpClient` with domain-specific methods and is\nregistered via `AddHttpClient\u003CT>`. In tests, use `WebApplicationFactory` to\nreplace the handler, or inject a mock handler via the factory.\n\n```csharp\n\u002F\u002F Production typed client:\npublic class WeatherClient\n{\n    private readonly HttpClient _http;\n    public WeatherClient(HttpClient http) => _http = http;\n\n    public async Task\u003CWeatherForecast?> GetForecastAsync(string city)\n    {\n        var response = await _http.GetAsync($\"\u002Fweather\u002F{city}\");\n        response.EnsureSuccessStatusCode();\n        return await response.Content.ReadFromJsonAsync\u003CWeatherForecast>();\n    }\n}\n\n\u002F\u002F Registered in Program.cs:\n\u002F\u002F builder.Services.AddHttpClient\u003CWeatherClient>(c =>\n\u002F\u002F c.BaseAddress = new Uri(\"https:\u002F\u002Fapi.weather.example.com\"));\n\n\u002F\u002F Integration test — replace the handler in the factory:\npublic class WeatherTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly WebApplicationFactory\u003CProgram> _factory;\n    public WeatherTests(WebApplicationFactory\u003CProgram> factory)\n        => _factory = factory;\n\n    [Fact]\n    public async Task GetForecast_WhenApiReturnsData_MapsCorrectly()\n    {\n        var fakeJson    = \"\"\"{\"city\":\"London\",\"tempC\":15}\"\"\";\n        var fakeHandler = new MockHttpMessageHandler(\n            new HttpResponseMessage(HttpStatusCode.OK)\n            { Content = new StringContent(fakeJson, Encoding.UTF8, \"application\u002Fjson\") });\n\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                \u002F\u002F Replace the named client handler:\n                services.AddHttpClient\u003CWeatherClient>()\n                        .ConfigurePrimaryHttpMessageHandler(() => fakeHandler);\n            });\n        }).CreateClient();\n\n        var response = await client.GetAsync(\"\u002Fapi\u002Fweather\u002Flondon\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n```\n\n**Rule of thumb:** Inject the handler at the `IHttpClientFactory` level rather\nthan constructing `HttpClient` directly in the class. This makes the handler\nswappable in tests without touching the typed client's code.\n",{"id":62,"difficulty":14,"q":63,"a":64},"output-caching-testing","How do you test endpoints that use response caching in integration tests?","Response caching in integration tests can produce false positives (a cached\nstale response masking a regression) or false negatives (the test bypasses\nthe cache entirely). You need to control the cache explicitly.\n\n```csharp\n\u002F\u002F Disable caching in the test factory so every test sees fresh responses:\nprotected override void ConfigureWebHost(IWebHostBuilder builder)\n{\n    builder.ConfigureServices(services =>\n    {\n        \u002F\u002F Replace the distributed cache with a no-op:\n        services.AddSingleton\u003CIDistributedCache, MemoryDistributedCache>();\n\n        \u002F\u002F Override response caching to have max-age=0:\n        services.Configure\u003CResponseCachingOptions>(opts =>\n            opts.MaximumBodySize = 0); \u002F\u002F disables body caching\n    });\n}\n\n\u002F\u002F Test caching behavior explicitly:\n[Fact]\npublic async Task CachedEndpoint_SecondRequest_ReturnsCachedResponse()\n{\n    \u002F\u002F First request — populates cache:\n    var r1 = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n    r1.EnsureSuccessStatusCode();\n    Assert.Equal(\"MISS\", r1.Headers.GetValues(\"X-Cache\").FirstOrDefault());\n\n    \u002F\u002F Second request — should hit cache:\n    var r2 = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n    r2.EnsureSuccessStatusCode();\n    Assert.Equal(\"HIT\", r2.Headers.GetValues(\"X-Cache\").FirstOrDefault());\n\n    \u002F\u002F Verify both return the same body:\n    var body1 = await r1.Content.ReadAsStringAsync();\n    var body2 = await r2.Content.ReadAsStringAsync();\n    Assert.Equal(body1, body2);\n}\n\n\u002F\u002F Reset cache between tests using IDistributedCache directly:\nvar cache = factory.Services.GetRequiredService\u003CIDistributedCache>();\nawait cache.RemoveAsync(\"products:all\");\n```\n\n**Rule of thumb:** Run most endpoint tests with caching disabled to avoid\nflaky test order dependencies. Write a dedicated, isolated test class for\ncaching behavior that explicitly populates and inspects cache state.\n",{"id":66,"difficulty":30,"q":67,"a":68},"problem-details-testing","How do you assert on ProblemDetails error responses in integration tests?","ASP.NET Core returns `ProblemDetails` (RFC 7807) for error responses when\n`AddProblemDetails()` is configured. Integration tests should assert on the\nstatus code, Content-Type, and specific problem fields.\n\n```csharp\n\u002F\u002F ProblemDetails shape:\n\u002F\u002F {\n\u002F\u002F \"type\": \"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7231#section-6.5.1\",\n\u002F\u002F \"title\": \"Bad Request\",\n\u002F\u002F \"status\": 400,\n\u002F\u002F \"detail\": \"The Sku field is required.\",\n\u002F\u002F \"instance\": \"\u002Fapi\u002Forders\"\n\u002F\u002F }\n\n[Fact]\npublic async Task PostOrder_WithMissingSku_Returns400ProblemDetails()\n{\n    var payload = new StringContent(\n        \"\"\"{\"quantity\":2}\"\"\", \u002F\u002F missing Sku\n        Encoding.UTF8, \"application\u002Fjson\");\n\n    var response = await _client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n\n    Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);\n    Assert.Equal(\"application\u002Fproblem+json\",\n        response.Content.Headers.ContentType!.MediaType);\n\n    \u002F\u002F Deserialize and assert specific fields:\n    var problem = await response.Content\n        .ReadFromJsonAsync\u003CProblemDetails>();\n\n    Assert.NotNull(problem);\n    Assert.Equal(400,         problem!.Status);\n    Assert.Contains(\"Sku\",    problem.Detail ?? \"\");\n}\n\n\u002F\u002F For validation errors, ASP.NET Core returns ValidationProblemDetails\n\u002F\u002F which has an Errors dictionary:\nvar validationProblem = await response.Content\n    .ReadFromJsonAsync\u003CValidationProblemDetails>();\nAssert.True(validationProblem!.Errors.ContainsKey(\"Sku\"));\n```\n\n**Rule of thumb:** Assert both the HTTP status code AND the Content-Type header\nin error response tests. A 400 returning `text\u002Fhtml` means the error middleware\nis misconfigured, even though the status code is correct.\n",{"id":70,"difficulty":14,"q":71,"a":72},"ef-core-migration-testing","How do you test that EF Core migrations apply cleanly in integration tests?","Running migrations in tests catches schema drift, broken migration scripts,\nand EF model\u002Fmigration mismatches before they reach production. The key is\nusing a real (or SQLite) database and calling `MigrateAsync()` in the fixture.\n\n```csharp\n\u002F\u002F MigrationTests — verify the full migration chain applies without error:\npublic class MigrationTests : IAsyncLifetime\n{\n    private SqliteConnection _connection = default!;\n    private AppDbContext     _db         = default!;\n\n    public async Task InitializeAsync()\n    {\n        _connection = new SqliteConnection(\"Data Source=:memory:\");\n        _connection.Open();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlite(_connection)\n            .Options;\n\n        _db = new AppDbContext(opts);\n\n        \u002F\u002F Apply every migration from scratch — fails if any script has an error:\n        await _db.Database.MigrateAsync();\n    }\n\n    [Fact]\n    public async Task AllMigrations_ApplyWithoutError()\n    {\n        \u002F\u002F If InitializeAsync succeeded, all migrations applied cleanly.\n        \u002F\u002F Verify the final schema contains expected tables:\n        var tables = await _db.Database\n            .SqlQueryRaw\u003Cstring>(\n                \"SELECT name FROM sqlite_master WHERE type='table'\")\n            .ToListAsync();\n\n        Assert.Contains(\"Orders\",   tables);\n        Assert.Contains(\"Products\", tables);\n        Assert.Contains(\"Customers\", tables);\n    }\n\n    [Fact]\n    public async Task PendingMigrations_AfterMigrate_IsEmpty()\n    {\n        \u002F\u002F Confirms no migration was accidentally left un-applied:\n        var pending = await _db.Database.GetPendingMigrationsAsync();\n        Assert.Empty(pending);\n    }\n\n    public async Task DisposeAsync()\n    {\n        await _db.DisposeAsync();\n        _connection.Close();\n    }\n}\n```\n\nOn SQL Server, use `EnsureDeleted()` + `MigrateAsync()` at the start of each\nCI run to test against a clean slate. For local dev speed, prefer SQLite.\n\n**Rule of thumb:** Run migration tests in CI on every branch. A migration that\ncannot be replayed from scratch on an empty database is a migration that will\nfail the first deployment to a new environment.\n",{"id":74,"difficulty":30,"q":75,"a":76},"replacing-services-in-factory","How do you replace or add services in WebApplicationFactory for specific test scenarios?","`WebApplicationFactory.WithWebHostBuilder` lets you override individual\nservices per test class without creating a whole new factory subclass.\nThis is cleaner when only one or two tests need a different service.\n\n```csharp\npublic class OrderIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly WebApplicationFactory\u003CProgram> _factory;\n\n    public OrderIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _factory = factory;\n\n    [Fact]\n    public async Task PlaceOrder_WhenEmailFails_StillReturnsCreated()\n    {\n        \u002F\u002F Replace only the email sender with a failing fake for this one test:\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                \u002F\u002F Remove the real registration:\n                var descriptor = services.Single(\n                    d => d.ServiceType == typeof(IEmailSender));\n                services.Remove(descriptor);\n\n                \u002F\u002F Add a fake that always throws:\n                services.AddSingleton\u003CIEmailSender, AlwaysFailingEmailSender>();\n            });\n        }).CreateClient();\n\n        var payload = new StringContent(\n            \"\"\"{\"sku\":\"X\",\"quantity\":1}\"\"\",\n            Encoding.UTF8, \"application\u002Fjson\");\n\n        \u002F\u002F Order creation should succeed even if email sending fails:\n        var response = await client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n    }\n\n    [Fact]\n    public async Task PlaceOrder_WithSlowInventoryCheck_RespectsTimeout()\n    {\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                var descriptor = services.Single(\n                    d => d.ServiceType == typeof(IInventoryService));\n                services.Remove(descriptor);\n\n                \u002F\u002F Slow fake simulates a lagging external dependency:\n                services.AddSingleton\u003CIInventoryService, SlowInventoryService>();\n            });\n        }).CreateClient();\n\n        var response = await client.PostAsync(\"\u002Fapi\u002Forders\",\n            new StringContent(\"\"\"{\"sku\":\"X\",\"quantity\":1}\"\"\",\n                Encoding.UTF8, \"application\u002Fjson\"));\n\n        Assert.Equal(HttpStatusCode.GatewayTimeout, response.StatusCode);\n    }\n}\n```\n\nEach call to `WithWebHostBuilder` returns a new factory instance with its own\n`HttpClient` and DI container — it does not mutate the shared fixture.\n\n**Rule of thumb:** Use `WithWebHostBuilder` for one-off service swaps within\na test method. Extract a subclass of `WebApplicationFactory` only when the\noverride is needed by an entire test class or multiple test classes.\n",{"id":78,"difficulty":14,"q":79,"a":80},"testing-background-services","How do you integration-test a hosted background service (IHostedService) in .NET?","`IHostedService` and `BackgroundService` implementations run on the host\nlifecycle. In tests, start the host, let the service execute, then verify\nits side effects (database writes, queue messages, outbox events).\n\n```csharp\n\u002F\u002F Background service that processes an outbox table every 5 seconds:\npublic class OutboxProcessor : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n    public OutboxProcessor(IServiceScopeFactory scopeFactory)\n        => _scopeFactory = scopeFactory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        while (!ct.IsCancellationRequested)\n        {\n            using var scope = _scopeFactory.CreateScope();\n            var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n\n            var pending = await db.OutboxMessages\n                .Where(m => !m.Sent).ToListAsync(ct);\n            foreach (var msg in pending)\n            {\n                \u002F\u002F Note: publish logic omitted for brevity\n                msg.Sent = true;\n            }\n            await db.SaveChangesAsync(ct);\n            await Task.Delay(TimeSpan.FromSeconds(5), ct);\n        }\n    }\n}\n\n\u002F\u002F Integration test — start the host, seed data, wait for processing:\n[Fact]\npublic async Task OutboxProcessor_MarksMessagesSent_WithinExpectedTime()\n{\n    \u002F\u002F Use a factory with fast polling (override the delay via config):\n    await using var factory = new WebApplicationFactory\u003CProgram>()\n        .WithWebHostBuilder(b =>\n        {\n            b.ConfigureAppConfiguration((_, cfg) =>\n                cfg.AddInMemoryCollection(new Dictionary\u003Cstring, string?>\n                {\n                    [\"OutboxPollingIntervalMs\"] = \"100\" \u002F\u002F fast for tests\n                }));\n        });\n\n    \u002F\u002F Seed an outbox message:\n    using var scope = factory.Services.CreateScope();\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    db.OutboxMessages.Add(new OutboxMessage { Payload = \"{}\", Sent = false });\n    await db.SaveChangesAsync();\n\n    \u002F\u002F Wait for the background service to process it:\n    var deadline = DateTime.UtcNow.AddSeconds(3);\n    bool sent    = false;\n    while (DateTime.UtcNow \u003C deadline)\n    {\n        await Task.Delay(150);\n        sent = await db.OutboxMessages.AnyAsync(m => m.Sent);\n        if (sent) break;\n    }\n\n    Assert.True(sent, \"OutboxProcessor did not mark messages sent within 3 seconds.\");\n}\n```\n\nFor services that poll on long intervals, inject the interval via configuration\nso tests can set it to milliseconds without modifying production code.\n\n**Rule of thumb:** Test background services against their observable side effects\n(DB state, queue contents), not their internal timer logic. Use short polling\nintervals in tests and a time-bounded wait loop rather than fixed `Task.Delay`.\n",{"id":82,"difficulty":30,"q":83,"a":84},"testing-minimal-apis","How do you integration-test Minimal API endpoints in ASP.NET Core?","Minimal APIs (introduced in .NET 6) register endpoints via `app.MapGet\u002FPost\u002F...`\nin `Program.cs`. They are tested exactly like controller endpoints — through\n`WebApplicationFactory` and `HttpClient` — but you assert on the response\nrather than on a controller action.\n\n```csharp\n\u002F\u002F Minimal API definition in Program.cs:\n\u002F\u002F app.MapPost(\"\u002Fapi\u002Fproducts\", async (CreateProductRequest req, IProductService svc) =>\n\u002F\u002F {\n\u002F\u002F var product = await svc.CreateAsync(req);\n\u002F\u002F return Results.Created($\"\u002Fapi\u002Fproducts\u002F{product.Id}\", product);\n\u002F\u002F })\n\u002F\u002F .WithName(\"CreateProduct\")\n\u002F\u002F .Produces\u003CProduct>(201)\n\u002F\u002F .ProducesProblem(400);\n\n\u002F\u002F Integration test:\npublic class ProductMinimalApiTests : IClassFixture\u003CCustomWebFactory>\n{\n    private readonly HttpClient _client;\n\n    public ProductMinimalApiTests(CustomWebFactory factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task CreateProduct_ValidRequest_Returns201WithLocationHeader()\n    {\n        var request = new { Name = \"Widget\", Price = 9.99 };\n        var payload = JsonContent.Create(request); \u002F\u002F sets Content-Type automatically\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Fproducts\", payload);\n\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n        Assert.NotNull(response.Headers.Location);\n\n        \u002F\u002F Deserialize the response body:\n        var product = await response.Content.ReadFromJsonAsync\u003CProduct>();\n        Assert.Equal(\"Widget\", product!.Name);\n    }\n\n    [Fact]\n    public async Task CreateProduct_MissingName_Returns400ValidationProblem()\n    {\n        var request = new { Price = 9.99 }; \u002F\u002F Name is missing\n        var payload = JsonContent.Create(request);\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Fproducts\", payload);\n\n        Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);\n\n        var problem = await response.Content\n            .ReadFromJsonAsync\u003CValidationProblemDetails>();\n        Assert.True(problem!.Errors.ContainsKey(\"Name\"));\n    }\n\n    [Fact]\n    public async Task GetProduct_AfterCreate_ReturnsCreatedProduct()\n    {\n        \u002F\u002F Round-trip test: POST then GET to confirm persistence:\n        var created  = await _client.PostAsync(\"\u002Fapi\u002Fproducts\",\n            JsonContent.Create(new { Name = \"Gadget\", Price = 24.99 }));\n        var location = created.Headers.Location!;\n\n        var getResp = await _client.GetAsync(location);\n        getResp.EnsureSuccessStatusCode();\n\n        var product = await getResp.Content.ReadFromJsonAsync\u003CProduct>();\n        Assert.Equal(\"Gadget\", product!.Name);\n    }\n}\n```\n\n**Rule of thumb:** Treat Minimal API tests as black-box HTTP tests — send a\nrequest, assert on status code, headers, and response body. Avoid reaching\ninto the handler implementation; if you need to verify a side effect (email\nsent, DB written), assert on the observable outcome.\n",15,null,{"description":11},"Integration testing interview questions — WebApplicationFactory, custom factories, SQLite vs in-memory databases, seeding data, and testing auth.","dotnet\u002Ftesting\u002Fintegration-testing","Testing","testing","2026-06-23","WFO_0uiTLGRvpTJtes3c41mkIKNASdgBpYJ9Im05y-Y",[95,99,102],{"subtopic":96,"path":97,"order":98},"Unit Testing","\u002Fdotnet\u002Ftesting\u002Funit-testing",1,{"subtopic":100,"path":101,"order":12},"Mocking","\u002Fdotnet\u002Ftesting\u002Fmocking",{"subtopic":6,"path":21,"order":20},{"path":104,"title":105},"\u002Fblog\u002Fdotnet-integration-testing","Integration Testing in ASP.NET Core with WebApplicationFactory",1782244120040]