Integration Testing C# with Docker: Advanced Level

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: Advanced Level

\n

Integration testing is a key quality assurance stage in modern .NET applications. Using Docker allows you to create isolated, reproducible environments that are as close to production as possible. In this article, we will explore advanced techniques for integration testing C# with Docker: from setting up Testcontainers to organizing CI/CD pipelines.

\n

The material is aimed at developers already familiar with the basics of unit testing and basic Docker concepts. We will delve into container lifecycle management, working with multiple services, debugging, and optimizing test execution time.

\n\n

1. Setting up Testcontainers for .NET

\n

Testcontainers is a library that manages Docker containers from test code. It automatically creates, starts, and stops containers, ensuring isolation for each test.

\n

To begin, install the package into your test project:

\n
dotnet add package Testcontainers
\n

A basic example — testing a repository with PostgreSQL:

\n
using Testcontainers.PostgreSql;\nusing Xunit;\n\npublic class UserRepositoryTests : IAsyncLifetime\n{\n    private readonly PostgreSqlContainer _postgresContainer;\n\n    public UserRepositoryTests()\n    {\n        // Configure the PostgreSQL container\n        _postgresContainer = new PostgreSqlBuilder()\n            .WithImage("postgres:15")\n            .WithDatabase("testdb")\n            .WithUsername("test")\n            .WithPassword("test123")\n            .WithCleanUp(true)\n            .Build();\n    }\n\n    public async Task InitializeAsync()\n    {\n        // Start the container before all tests\n        await _postgresContainer.StartAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        // Stop and remove the container\n        await _postgresContainer.DisposeAsync();\n    }\n\n    [Fact]\n    public async Task AddUser_ShouldCreateUser()\n    {\n        // Get the connection string to the container\n        var connectionString = _postgresContainer.GetConnectionString();\n        var repository = new UserRepository(connectionString);\n\n        await repository.AddUserAsync(new User { Name = "Test User" });\n        var user = await repository.GetUserByNameAsync("Test User");\n\n        Assert.NotNull(user);\n        Assert.Equal("Test User", user.Name);\n    }\n}
\n

Important: use IAsyncLifetime to manage the container. This ensures that each test class gets a fresh database instance.

\n\n

2. Multi-container Architecture with Docker Compose

\n

Real applications depend on multiple services: databases, message queues, caches. Testcontainers supports Docker Compose, allowing you to run an entire infrastructure.

\n

Install the additional package:

\n
dotnet add package Testcontainers.Compose
\n

Example docker-compose.test.yml file:

\n
version: '3.8'\nservices:\n  postgres:\n    image: postgres:15\n    environment:\n      POSTGRES_USER: test\n      POSTGRES_PASSWORD: test\n      POSTGRES_DB: testdb\n  redis:\n    image: redis:7-alpine
\n

Usage in a test:

\n
using Testcontainers.Compose;\n\npublic class OrderServiceTests\n{\n    private readonly DockerComposeContainer _compose;\n\n    public OrderServiceTests()\n    {\n        _compose = new DockerComposeContainer()\n            .WithComposeFilePath("docker-compose.test.yml")\n            .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Testing")\n            .Build();\n    }\n\n    [Fact]\n    public async Task CreateOrder_ShouldSaveToDbAndCache()\n    {\n        await _compose.StartAsync();\n        \n        var dbConnection = _compose.GetConnectionString("postgres", 5432);\n        var redisConnection = _compose.GetConnectionString("redis", 6379                

Blogs

Book Recommendations