How to Create a Testcontainers for .NET Module for Wider Ecosystem
December 8, 2025 · 1063 words · 5 min
Testcontainers libraries make it easy to create reliable tests by allowing your unit tests to run wi
Testcontainers libraries make it easy to create reliable tests by allowing your unit tests to run with real dependencies. Anything that runs in containers can become a part of your tests with just a few lines of code: from databases and message brokers to Kubernetes clusters and cloud solutions for testing. Flexible API and attention to detail like automatic cleanup and mapped ports randomization made Testcontainers a widely-adopted solution. Still, one thing that elevates Testcontainers even more is the ecosystem of modules — pre-configured abstractions that allow you to test applications with specific technologies without configuring the containers yourself. And now, with the recent , there’s better support for modules than ever before. In this article, we’ll look at how to create a Testcontainers for .NET module for your favorite technology, how to add capabilities to the module so common configuration options are added in the API, and where to look for a good example of a module. Testcontainers for .NET offers two ways of implementing a module, depending on the complexity of the use case. For simple modules, developers can inherit from the class. It provides a straightforward way to build a module and configure it as needed. For more advanced use cases, Testcontainers for .NET provides a second option for developers to inherit from . This class offers a more flexible and powerful way to build modules and provides access to additional features and configurations. Both approaches allow developers to share and reuse their configurations and best practices. They’re also a simple and consistent way to spin up containers. The Testcontainers for .NET repository contains a .NET to scaffold advanced modules quickly. To create and add a new module to the Testcontainers solution file, check out the repository and install the .NET template first: The following CLI commands create and add a new PostgreSQL module to the solution file: A module in Testcontainers for .NET typically consists of three classes representing the builder, configuration, and container. The PostgreSQL module we just created above consists of the , , and classes. The next steps guide you through the process of creating a new module for Testcontainers for .NET. We’ll first show how to override and extend the default configuration provided by the class. After that, we’ll explain how to add new members to the builder and configuration classes. By doing this, you extend the capabilities of the builder and configuration to support more complex use cases. The configuration classes in Testcontainers for .NET are designed to be immutable. In other words, once an instance of a configuration class is created, its values cannot be changed. This makes it more reliable, easier to understand, and better to share between different use cases like A/B testing. To set the PostgreSQL module default configuration, override the read-only property in and set its value in both constructors. The default constructor sets to the return value of , where the overloaded private constructor just sets the argument value. It receives an updated instance of the immutable Docker resource configuration as soon as a property changes. The .NET template already includes this configuration, making it easy for developers to quickly get started by simply commenting out the necessary parts. To append the PostgreSQL configurations to the default Testcontainers configurations, override or comment out the member . Then, add the necessary configurations, such as the Docker image and a wait strategy to the base implementation. When using the PostgreSQL Docker image, it’s required to have a password set in order to run it. To demonstrate how to add a new builder capability, we’ll use this requirement as an example. First, add a new property to the class. Then, add a password argument with a default value of null to the default constructor. This allows the builder to set individual arguments or configurations. The overloaded constructor takes care of merging the configurations together. The builder will receive and hold an updated instances that contains all information: Since the class is now able to store the password value, we can add a member to . We don’t just store the password in the instance to construct the database connection string later. But we also set the necessary environment variable to run the container. By following this approach, the class is able to access the configured values. This opens up additional functionalities, such as constructing the database connection string. This enables the class to provide a more streamlined and convenient experience for developers who are working with modules. Finally, there’re two approaches to ensure that the required password is provided. Either override the member and check the immutable configuration instance: or extend the member as we have already done and add to set a default value. It’s always a good idea to add both approaches. This way, the user can be sure that the module is properly configured, whether by themself or by default. This helps maintain a consistent and reliable experience for the user. Following it, when creating your own modules, either in-house or public, you can be a role model for other developers too. The Testcontainers for .NET repository provides a reference implementation of the Microsoft SQL Server . This module is a comprehensive example and can serve as a guide for you to get a better understanding of how to implement an entire module including ! Testcontainers for .NET offers a streamlined and flexible way to spin up test dependencies. By utilizing the .NET template for the new modules, developers can take advantage of the pre-existing configurations and easily extend them with custom abstractions. This helps to grow the ecosystem of the technologies you can use to test applications against with just a few lines of code. And this is made possible without requiring the end-developer to do the low-level configuration like specifying what ports to expose or paths to put the config files in the container. Great use cases for the modules include public contributions to the Testcontainers for .NET project to support your favorite database or technology and also in-house abstractions to help your colleagues keep up with best practices. All in all, by following the steps outlined in this article, you can easily extend the capabilities of Testcontainers for .NET and make the most out of their testing setup.