Testcontainers for .NET
repository·develop·Indexed 26 days ago
https://github.com/testcontainers/testcontainers-dotnetA library for .NET that provides programmatic control over Docker containers to facilitate integration testing. It enables developers to spin up, manage, and tear down isolated, disposable container instances. The library supports all compatible .NET Standard versions and includes features for custom connection string providers, resource mapping, and integration with tools like Flyway and Respawn.
What's inside testcontainers-dotnet
- Testcontainers for .NET is a library that enables developers to run tests using throwaway instances of Docker containers. It supports all compatible .NET Standard versions and is built on top of the .NET Docker Remote API, providing a lightweight way to manage test environments using Docker.
Implement module architecture
developA Testcontainers module typically consists of three core classes:
- Builder Class (e.g.,
PostgreSqlBuilder): Extends the Testcontainers builder. It manages the lifecycle, sets default configurations, validates inputs, and provides the API for developers to interact with the module. The result of the builder is an instance of the container class. - Configuration Class (e.g.,
PostgreSqlConfiguration): An immutable class that stores optional members used to configure the module (e.g.,Username,Password). - Container Class (e.g.,
PostgreSqlContainer): The object returned by the builder. It provides module-specific methods to interact with the running container (e.g., retrieving connection strings).
- Builder Class (e.g.,
Use Redis with Testcontainers in .NET
developYou can start a Redis container instance from any .NET application. When using testing frameworks like xUnit.net, it is recommended to implement theIAsyncLifetimeinterface to manage the container lifecycle. Start the container inInitializeAsyncto ensure the environment is ready before tests run, and dispose of it inDisposeAsyncto ensure the container is removed after tests complete.Configure stable names for Networks and Volumes to enable reuse
developResource reuse requires stable configurations. By default,
NetworkBuilderandVolumeBuilderassign random names to resources, which causes the reuse hash to change every time. To enable reuse for these resources, you must override the default random name with a fixed value using.WithName()._ = new NetworkBuilder() .WithReuse(true) .WithName("WeatherForecast");Use RabbitMQ containers in .NET tests
developYou can manage the lifecycle of a RabbitMQ container instance within your tests. A common pattern is to use xUnit.net'sIAsyncLifetimeinterface: start the container inInitializeAsyncto ensure the environment is ready before tests run, and remove it inDisposeAsyncafter tests complete.Connect to containers using Hostname instead of localhost
developDo not uselocalhostor127.0.0.1to connect to a container from your test host. Use theHostnameproperty of the container instance to ensure reliable connectivity.Configure container-to-container communication with Network Aliases
developWhen setting up communication between multiple containers, useWithNetworkAliases(string)to assign an alias. Other containers on the same network can then access the service via this alias using its internal container port.Configure Elasticsearch client for HTTPS communication
developThe Elasticsearch container created by this module listens for requests over HTTPS. Because the container uses a self-signed certificate, the .NET client will reject the connection by default. To fix this, you must create anElasticsearchClientSettingsinstance and set theServerCertificateValidationCallbackdelegate toCertificateValidations.AllowAll.Configure Toxiproxy for network resiliency testing
developTo simulate network conditions between a service and a test host using Toxiproxy, follow these steps:
- Network Setup: Place both the Toxiproxy container and the target service container (e.g., Redis) in the same Docker network so they can communicate.
- Proxy Configuration: Configure a proxy within Toxiproxy. The
Listenaddress is where Toxiproxy accepts incoming connections from your test host, and theUpstreamaddress is the target service's address. - Connection: Instead of connecting directly to the service, connect your application to the Toxiproxy container's hostname using one of the proxied ports. The module initializes 32 ports starting from
8666for this purpose. - Apply Toxics: Apply 'toxics' to the proxy to simulate specific conditions like latency or connection issues. You can set the
Toxicityproperty (a value between0.0and1.0) to control the probability of the toxic being applied to a connection.
Copy the Ryuk image to a private registry using Skopeo
developTo maintain multi-architecture support and preserve digests when moving the Ryuk image to a private registry, use the following commands. The pinned digest for Testcontainers for .NET is
testcontainers/ryuk:0.14.0@sha256:7c1a8a9a47c780ed0f983770a662f80deb115d95cce3e2daa3d12115b8cd28f0.### Linux/macOS ```shell skopeo \ copy \ --all \ --preserve-digests \ docker://docker.io/testcontainers/ryuk@sha256:7c1a8a9a47c780ed0f983770a662f80deb115d95cce3e2daa3d12115b8cd28f0 \ docker://registry.mycompany.com/testcontainers/ryuk:0.14.0Windows
# There's no Skopeo package for Windows. Use the Skopeo Docker image: docker run ` --rm ` quay.io/skopeo/stable:v1.22.0 ` copy ` --all ` --preserve-digests ` docker://docker.io/testcontainers/ryuk@sha256:7c1a8a9a47c780ed0f983770a662f80deb115d95cce3e2daa3d12115b8cd28f0 ` docker://registry.mycompany.com/testcontainers/ryuk:0.14.0Start a PostgreSQL container
developYou can start a PostgreSQL container instance by using the
PostgreSqlBuilder. Specify the desired image tag (e.g.,postgres:15.1) in the constructor, call.Build(), and thenawait .StartAsync()to launch the container.var postgreSqlContainer = new PostgreSqlBuilder("postgres:15.1").Build(); await postgreSqlContainer.StartAsync();Configure Docker Compose for Testcontainers in a container
developTo run tests via Docker Compose where the test runner itself is a container, you must mount the raw Docker socket and potentially configure the host override.
Note for Docker Desktop users: You must uncomment and include the
environmentsection withTESTCONTAINERS_HOST_OVERRIDE=host.docker.internal. This is not required when using standard Docker Engine.version: "3" services: docker_compose_test: build: dockerfile: Dockerfile context: . entrypoint: dotnet command: test # Uncomment the lines below in the case of Docker Desktop (see note above). # TESTCONTAINERS_HOST_OVERRIDE is not needed in the case of Docker Engine. # environment: # - TESTCONTAINERS_HOST_OVERRIDE=host.docker.internal volumes: - /var/run/docker.sock.raw:/var/run/docker.sock