Integration Testing C# with Docker: A Complete A-to-Z Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Integration Testing C# with Docker: From A to Z

\n\n

Integration testing is a critically important stage in developing any serious C# application. It checks how various system components (database, external APIs, file systems) work together. However, setting up a test environment often becomes a headache: you need to spin up real servers, clean up data after tests, and deal with environment instability. Docker solves these problems by providing lightweight, isolated, and reproducible containers. In this article, we will break down how to set up integration testing C# with Docker from scratch to a working pipeline.

\n\n

Why Docker is Ideal for Integration Tests in C#?

\n\n

The traditional approach is to use local SQL Server databases or emulators of external services. This leads to problems:

\n
    \n
  • Data pollution: tests leave garbage in the database, affecting other tests.
  • \n
  • Environment incompatibility: one version of the DBMS on the developer's machine, another on the CI server.
  • \n
  • Difficulty of parallel execution: tests conflict over ports and resources.
  • \n
\n\n

Docker solves this simply: each test (or group of tests) gets its own isolated container with the required version of the database, Redis, or another service. Containers are lightweight, start in seconds, and are guaranteed to be destroyed after the tests finish. For .NET developers, this is especially relevant thanks to the Testcontainers for .NET library, which automates container management directly from the test code.

\n\n

Project Setup: Adding Docker to C# Tests

\n\n

First, let's create a project with integration tests. Let's assume we have a web API on .NET 8 that works with PostgreSQL. We need to test the user creation endpoint.

\n\n

Step 1: Installing NuGet Packages

\n

Add the following packages to the test project:

\n
dotnet add package Testcontainers.PostgreSql\ndotnet add package Microsoft.AspNetCore.Mvc.Testing\ndotnet add package FluentAssertions
\n\n

Testcontainers.PostgreSql is a wrapper over the Docker SDK that manages PostgreSQL containers. Microsoft.AspNetCore.Mvc.Testing allows you to run the web application in memory for testing.

\n\n

Step 2: Creating a Base Class for Tests

\n

Let's create an abstract class that will spin up a database container before the tests:

\n
using Testcontainers.PostgreSql;\nusing Xunit;\n\npublic abstract class IntegrationTestBase : IAsyncLifetime\n{\n    private readonly PostgreSqlContainer _postgresContainer;\n\n    protected string ConnectionString => _postgresContainer.GetConnectionString();\n\n    protected IntegrationTestBase()\n    {\n        _postgresContainer = new PostgreSqlBuilder()\n            .WithImage("postgres:16-alpine")\n            .WithDatabase("testdb")\n            .WithUsername("test")\n            .WithPassword("test123")\n            .Build();\n    }\n\n    public async Task InitializeAsync()\n    {\n        await _postgresContainer.StartAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        await _postgresContainer.StopAsync();\n    }\n}
\n\n

This class implements IAsyncLifetime from xUnit, which guarantees starting the container before all tests and stopping it after. The ConnectionString is dynamically obtained from the container — the port can be any available one.

\n\n

Step 3: Writing a Test with Testcontainers and WebApplicationFactory

\n

Now let's write the test itself. We will use WebApplicationFactory to create a test HTTP client:

\n
using Microsoft.AspNetCore.Mvc.Testing;\nusing FluentAssertions;\nusing System.Net.Http.Json;\n\npublic class UserApiTests : IntegrationTestBase\n{\n    private readonly WebApplicationFactory<Program> _factory;\n\n    public UserApiTests()\n                

Blogs

Book Recommendations