Course contentsShow
← C#
Lesson 1867 of 1,90817. Deployment and Cloud ArchitectureFree lesson

Automated Unit and Integration Testing in Containers

Execute containerized test runners that verify .NET logic against database dependencies.

Automated Unit and Integration Testing in Containers

In this lesson, you will learn how to orchestrate isolated, ephemeral environments that allow your .NET test suite to verify business logic against real database dependencies.

When testing .NET microservices, mocking a database interface is often insufficient; true integration testing requires verifying that your entity configurations, migrations, and repository queries function correctly against an actual engine like PostgreSQL or SQL Server. Running these tests directly on a developer’s machine or a static CI agent leads to "it works on my machine" syndrome due to environment drift.

The solution is to containerize the test runner itself. By packaging your test project into a lightweight Docker image, you encapsulate the exact runtime environment, .NET SDK version, and test dependencies.

Orchestrating the Test Environment

Using a docker-compose.test.yml file, you can spin up a transient database service alongside your test runner container. The test runner waits for the database to be "Ready" (often using a simple health-check script) before executing the dotnet test command.

version: '3.8'
services:
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: TestDb
  test-runner:
    build:
      context: .
      dockerfile: Dockerfile.Test
    depends_on:
      - db
    environment:
      - ConnectionString=Host=db;Database=TestDb;Username=postgres;Password=password

Inside your Dockerfile.Test, you typically use a multi-stage build to restore dependencies and run the tests. The container exits with a non-zero code if any tests fail, allowing your CI/CD pipeline to automatically block a deployment if the integration requirements are not met. Because these containers are ephemeral, you ensure a "clean room" start for every test run, preventing data pollution from previous sessions.

This approach transforms your integration suite into a portable asset. Whether running locally, in a GitHub Action, or within your Kubernetes build pipeline, the environment remains consistent, ensuring that your data-access logic is verified against a production-like infrastructure before you ever deploy to the cluster.

Key Takeaway: By wrapping your test execution in a container alongside its required database dependencies, you eliminate environmental inconsistencies and guarantee that your integration tests reflect the actual state of your infrastructure.