Skip to content

Conversation

@HofmeisterAn
Copy link
Collaborator

What does this PR do?

The PR delegates the string constructor to IImage, which reduces copy-and-paste code.

Why is it important?

-

Related issues

-

@HofmeisterAn HofmeisterAn added the chore A change that doesn't impact the existing functionality, e.g. internal refactorings or cleanups label Dec 7, 2025
@netlify
Copy link

netlify bot commented Dec 7, 2025

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit d924c7b
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/6935c11b49acb80009f9c87f
😎 Deploy Preview https://deploy-preview-1600--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Summary by CodeRabbit

Release Notes

Refactor

  • Streamlined builder initialization patterns across numerous modules to use a unified Docker image abstraction layer
  • Improved internal code consistency and maintainability with standardized constructor delegation patterns
  • No impact on public APIs or existing functionality

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This pull request systematically refactors string-based constructor initialization across approximately 50 builder classes and a template file. The change converts constructor delegation from XxxConfiguration instances to DockerImage(image), moving Docker image configuration responsibility to dedicated IImage-based constructor paths. The public signatures remain unchanged.

Changes

Cohort / File(s) Summary
Builder Constructor Refactoring (String Image → DockerImage)
src/Testcontainers.*/\*Builder.cs (ActiveMq, ArangoDb, Azurite, BigQuery, Bigtable, Cassandra, ClickHouse, CockroachDb, CosmosDb, CouchDb, Couchbase, Db2, DynamoDb, Elasticsearch, EventHubs, FakeGcsServer, FirebirdSql, Firestore, Grafana, InfluxDb, Kafka, Keycloak, KurrentDb, Kusto, LocalStack, LowkeyVault, MariaDb, Milvus, Minio, MongoDb, Mosquitto, MsSql, MySql, Nats, Neo4j, Ollama, OpenSearch, Oracle, Papercut, Playwright, PostgreSql, PubSub, Pulsar, Qdrant, RabbitMq, RavenDb, Redis, Redpanda, ServiceBus, Sftp, Toxiproxy, Typesense, Weaviate, WebDriver), src/Testcontainers/Builders/ContainerBuilder.cs
Converts string-parameter constructor initialization from new XxxConfiguration() to new DockerImage(image). Removes inline DockerResourceConfiguration assignment statements, delegating image configuration to IImage-based constructor paths.
New IImage Overloads
src/Testcontainers.BigQuery/BigQueryBuilder.cs, src/Testcontainers.Consul/ConsulBuilder.cs, src/Testcontainers.JanusGraph/JanusGraphBuilder.cs, src/Testcontainers.Redpanda/RedpandaBuilder.cs, src/Testcontainers.Toxiproxy/ToxiproxyBuilder.cs
Adds public XxxBuilder(IImage image) constructor overloads that initialize with fresh configuration objects and set DockerResourceConfiguration via Init().WithImage(image).
Template & Global Usings
src/Templates/CSharp/Testcontainers.ModuleName/ModuleNameBuilder.cs, src/Templates/CSharp/Testcontainers.ModuleName/Usings.cs
Updates template module builder to use DockerImage(image) pattern; adds global using directive for DotNet.Testcontainers.Images.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Scope: ~52 files modified with consistent but repetitive changes requires systematic verification
  • Complexity: Pattern is straightforward (constructor delegation swap) but applied across numerous builder classes
  • Key review areas:
    • Verify consistent application of pattern across all builder files
    • Confirm IImage constructor overloads are added only where needed (5 files)
    • Check that no builders deviate from the standard pattern
    • Validate that DockerResourceConfiguration initialization removed from all affected string constructors
    • Ensure template changes align with production builder implementations

Possibly related PRs

Poem

🐰 A thousand builders, all in line,
Swapped their config-strings so fine,
DockerImage now leads the way,
While delegation saves the day!
No signatures bent or broke,
Just cleaner paths—a rabbit's joke! 🎯

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is incomplete. While it explains WHAT the PR does, the mandatory 'Why is it important?' section is missing substantive content (only shows a dash), and recommended sections for testing instructions and related issues lack details. Expand the 'Why is it important?' section to explain the benefits (reduced duplication, consistency, maintainability), and optionally add testing guidance or related issue references.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: delegating container builder string constructors to IImage overloads, which is the consistent pattern across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/delegate-to-ctor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/Testcontainers.RabbitMq/RabbitMqBuilder.cs (1)

35-38: LGTM! Clean refactoring that reduces duplication.

The constructor delegation to the IImage overload via new DockerImage(image) eliminates duplicate initialization logic while preserving identical behavior. This follows the DRY principle and consolidates the image setup flow into a single code path.

src/Testcontainers.FirebirdSql/FirebirdSqlBuilder.cs (1)

49-50: Fix malformed XML documentation (pre-existing).

The XML documentation for the image parameter is missing the opening <param name="image"> tag and closing </param> tag.

Apply this diff to fix the documentation:

-/// An <see cref="IImage" /> instance that specifies the Docker image to be used
-/// for the container builder configuration.
+/// <param name="image">An <see cref="IImage" /> instance that specifies the Docker image to be used
+/// for the container builder configuration.</param>
src/Templates/CSharp/Testcontainers.ModuleName/ModuleNameBuilder.cs (1)

17-28: Template: string constructor now mirrors real modules’ pattern

Changing ModuleNameBuilder(string image) to delegate to : this(new DockerImage(image)) matches the pattern used in the concrete builders and is supported by the new DotNet.Testcontainers.Images global using. Given this is scaffolding and the image wiring is intentionally commented out in the IImage constructor, there’s no behavioral regression—just a clearer template for module authors.

If you want to make the template more instructive, consider adding a short comment near the IImage constructor explaining that authors should typically wire the image there via Init().WithImage(image), as done in the real modules.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed192fb and d924c7b.

📒 Files selected for processing (60)
  • src/Templates/CSharp/Testcontainers.ModuleName/ModuleNameBuilder.cs (1 hunks)
  • src/Templates/CSharp/Testcontainers.ModuleName/Usings.cs (1 hunks)
  • src/Testcontainers.ActiveMq/ArtemisBuilder.cs (1 hunks)
  • src/Testcontainers.ArangoDb/ArangoDbBuilder.cs (1 hunks)
  • src/Testcontainers.Azurite/AzuriteBuilder.cs (1 hunks)
  • src/Testcontainers.BigQuery/BigQueryBuilder.cs (1 hunks)
  • src/Testcontainers.Bigtable/BigtableBuilder.cs (1 hunks)
  • src/Testcontainers.Cassandra/CassandraBuilder.cs (1 hunks)
  • src/Testcontainers.ClickHouse/ClickHouseBuilder.cs (1 hunks)
  • src/Testcontainers.CockroachDb/CockroachDbBuilder.cs (1 hunks)
  • src/Testcontainers.Consul/ConsulBuilder.cs (1 hunks)
  • src/Testcontainers.CosmosDb/CosmosDbBuilder.cs (1 hunks)
  • src/Testcontainers.CouchDb/CouchDbBuilder.cs (1 hunks)
  • src/Testcontainers.Couchbase/CouchbaseBuilder.cs (1 hunks)
  • src/Testcontainers.Db2/Db2Builder.cs (1 hunks)
  • src/Testcontainers.DynamoDb/DynamoDbBuilder.cs (1 hunks)
  • src/Testcontainers.Elasticsearch/ElasticsearchBuilder.cs (1 hunks)
  • src/Testcontainers.EventHubs/EventHubsBuilder.cs (1 hunks)
  • src/Testcontainers.FakeGcsServer/FakeGcsServerBuilder.cs (1 hunks)
  • src/Testcontainers.FirebirdSql/FirebirdSqlBuilder.cs (1 hunks)
  • src/Testcontainers.Firestore/FirestoreBuilder.cs (1 hunks)
  • src/Testcontainers.Grafana/GrafanaBuilder.cs (1 hunks)
  • src/Testcontainers.InfluxDb/InfluxDbBuilder.cs (1 hunks)
  • src/Testcontainers.JanusGraph/JanusGraphBuilder.cs (1 hunks)
  • src/Testcontainers.K3s/K3sBuilder.cs (1 hunks)
  • src/Testcontainers.Kafka/KafkaBuilder.cs (1 hunks)
  • src/Testcontainers.Keycloak/KeycloakBuilder.cs (1 hunks)
  • src/Testcontainers.KurrentDb/KurrentDbBuilder.cs (1 hunks)
  • src/Testcontainers.Kusto/KustoBuilder.cs (1 hunks)
  • src/Testcontainers.LocalStack/LocalStackBuilder.cs (1 hunks)
  • src/Testcontainers.LowkeyVault/LowkeyVaultBuilder.cs (1 hunks)
  • src/Testcontainers.MariaDb/MariaDbBuilder.cs (1 hunks)
  • src/Testcontainers.Milvus/MilvusBuilder.cs (1 hunks)
  • src/Testcontainers.Minio/MinioBuilder.cs (1 hunks)
  • src/Testcontainers.MongoDb/MongoDbBuilder.cs (1 hunks)
  • src/Testcontainers.Mosquitto/MosquittoBuilder.cs (1 hunks)
  • src/Testcontainers.MsSql/MsSqlBuilder.cs (1 hunks)
  • src/Testcontainers.MySql/MySqlBuilder.cs (1 hunks)
  • src/Testcontainers.Nats/NatsBuilder.cs (1 hunks)
  • src/Testcontainers.Neo4j/Neo4jBuilder.cs (1 hunks)
  • src/Testcontainers.Ollama/OllamaBuilder.cs (1 hunks)
  • src/Testcontainers.OpenSearch/OpenSearchBuilder.cs (1 hunks)
  • src/Testcontainers.Oracle/OracleBuilder.cs (1 hunks)
  • src/Testcontainers.Papercut/PapercutBuilder.cs (1 hunks)
  • src/Testcontainers.Playwright/PlaywrightBuilder.cs (1 hunks)
  • src/Testcontainers.PostgreSql/PostgreSqlBuilder.cs (1 hunks)
  • src/Testcontainers.PubSub/PubSubBuilder.cs (1 hunks)
  • src/Testcontainers.Pulsar/PulsarBuilder.cs (1 hunks)
  • src/Testcontainers.Qdrant/QdrantBuilder.cs (1 hunks)
  • src/Testcontainers.RabbitMq/RabbitMqBuilder.cs (1 hunks)
  • src/Testcontainers.RavenDb/RavenDbBuilder.cs (1 hunks)
  • src/Testcontainers.Redis/RedisBuilder.cs (1 hunks)
  • src/Testcontainers.Redpanda/RedpandaBuilder.cs (1 hunks)
  • src/Testcontainers.ServiceBus/ServiceBusBuilder.cs (1 hunks)
  • src/Testcontainers.Sftp/SftpBuilder.cs (1 hunks)
  • src/Testcontainers.Toxiproxy/ToxiproxyBuilder.cs (1 hunks)
  • src/Testcontainers.Typesense/TypesenseBuilder.cs (1 hunks)
  • src/Testcontainers.Weaviate/WeaviateBuilder.cs (1 hunks)
  • src/Testcontainers.WebDriver/WebDriverBuilder.cs (1 hunks)
  • src/Testcontainers/Builders/ContainerBuilder.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-17T17:58:43.958Z
Learnt from: diegosasw
Repo: testcontainers/testcontainers-dotnet PR: 1583
File: src/Testcontainers.KurrentDb/Testcontainers.KurrentDb.csproj:7-7
Timestamp: 2025-11-17T17:58:43.958Z
Learning: In the testcontainers-dotnet repository, JetBrains.Annotations should use version 2023.3.0 to maintain consistency with the main Testcontainers csproj, rather than always using the latest available version.

Applied to files:

  • src/Templates/CSharp/Testcontainers.ModuleName/Usings.cs
📚 Learning: 2025-11-10T09:58:21.688Z
Learnt from: verdie-g
Repo: testcontainers/testcontainers-dotnet PR: 1569
File: src/Testcontainers.Milvus/MilvusBuilder.cs:67-67
Timestamp: 2025-11-10T09:58:21.688Z
Learning: In Milvus test containers (src/Testcontainers.Milvus/MilvusBuilder.cs), the DEPLOY_MODE=STANDALONE environment variable is a valid and official configuration option used in Milvus standalone deployments, as documented in the official Milvus standalone_embed.sh script.

Applied to files:

  • src/Testcontainers.Milvus/MilvusBuilder.cs
🧬 Code graph analysis (3)
src/Testcontainers.MongoDb/MongoDbBuilder.cs (1)
src/Testcontainers/Images/DockerImage.cs (4)
  • DockerImage (38-41)
  • DockerImage (48-51)
  • DockerImage (62-75)
  • DockerImage (77-112)
src/Testcontainers/Builders/ContainerBuilder.cs (1)
src/Testcontainers/Images/DockerImage.cs (4)
  • DockerImage (38-41)
  • DockerImage (48-51)
  • DockerImage (62-75)
  • DockerImage (77-112)
src/Testcontainers.Keycloak/KeycloakBuilder.cs (1)
src/Testcontainers/Images/DockerImage.cs (4)
  • DockerImage (38-41)
  • DockerImage (48-51)
  • DockerImage (62-75)
  • DockerImage (77-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: ci (Testcontainers.Bigtable, ubuntu-24.04)
  • GitHub Check: ci (Testcontainers.Cassandra, ubuntu-24.04)
  • GitHub Check: ci (Testcontainers.BigQuery, ubuntu-24.04)
  • GitHub Check: ci (Testcontainers.ArangoDb, ubuntu-24.04)
  • GitHub Check: ci (Testcontainers.ActiveMq, ubuntu-24.04)
  • GitHub Check: analyze (csharp)
🔇 Additional comments (62)
src/Testcontainers.DynamoDb/DynamoDbBuilder.cs (1)

31-34: LGTM!

Clean refactor that delegates to the IImage constructor, centralizing image handling and reducing code duplication. The constructor chain (stringIImageprivate) is well-structured.

src/Testcontainers.Ollama/OllamaBuilder.cs (1)

31-34: Constructor delegation to IImage overload looks correct

The string-based constructor cleanly delegates to the IImage-based overload via new DockerImage(image), which removes duplication and keeps all initialization logic in one place. Public surface and behavior are preserved while aligning this builder with the shared pattern used elsewhere.

src/Testcontainers.PubSub/PubSubBuilder.cs (1)

31-34: String constructor delegation to IImage path is consistent and appropriate

Routing PubSubBuilder(string image) through this(new DockerImage(image)) cleanly reuses the IImage-based constructor and centralizes image configuration via Init().WithImage(image). This removes duplication without changing the public API and aligns with the pattern used in other builders in this PR.

src/Testcontainers.Bigtable/BigtableBuilder.cs (1)

31-34: Constructor delegation to IImage-based path looks good

Routing the string ctor through new DockerImage(image) and the existing IImage overload centralizes image configuration and removes duplication while keeping the public API unchanged. No issues spotted.

src/Testcontainers.Sftp/SftpBuilder.cs (1)

37-40: Ctor delegation to IImage looks good and reduces duplication

Routing the string-based constructor through new DockerImage(image) into the IImage overload keeps a single initialization path (Init().WithImage(image)), which improves maintainability without changing the public API or behavior.

src/Testcontainers.CockroachDb/CockroachDbBuilder.cs (1)

39-42: LGTM! Clean delegation pattern reduces code duplication.

The refactoring correctly delegates the string constructor to the IImage constructor via DockerImage, eliminating duplicate initialization logic while preserving the same behavior. This aligns with the PR's objective to centralize image configuration through the IImage interface.

src/Testcontainers.Qdrant/QdrantBuilder.cs (1)

37-40: LGTM! Constructor delegation successfully refactored.

The string constructor now properly delegates to the IImage-based constructor path via new DockerImage(image), eliminating the previous inline Init().WithImage(image) assignment. This centralizes image configuration logic and reduces code duplication while maintaining identical public API behavior.

src/Testcontainers.Nats/NatsBuilder.cs (1)

35-38: String ctor delegation to IImage via DockerImage looks consistent with the new pattern.

The change to delegate NatsBuilder(string image) to NatsBuilder(IImage image) using new DockerImage(image) nicely centralizes all image handling in the IImage-based path and removes duplicate Init().WithImage(image) logic. This matches the refactor described for the rest of the PR.

One thing to double‑check: does DockerImage(string) have the same validation/normalization semantics as the previous string‑based WithImage(image) call (e.g., null/empty string, missing tag)? If there are edge‑case differences, it might be worth adding/adjusting a couple of tests around the string ctor to ensure behavior remains backward‑compatible.

src/Testcontainers.Pulsar/PulsarBuilder.cs (1)

41-44: LGTM! Clean constructor delegation.

The refactoring correctly delegates the string constructor to the IImage-based overload via DockerImage(image), eliminating duplication while preserving the public API. The delegation chain is clear and consistent with the pattern applied across other builders.

src/Testcontainers.EventHubs/EventHubsBuilder.cs (1)

37-40: LGTM! Constructor delegation reduces code duplication.

The change properly delegates the string constructor to the IImage constructor path by wrapping the string in DockerImage(image). This eliminates duplicate initialization logic while preserving the same behavior—the IImage constructor (lines 50-54) still calls Init().WithImage(image) as before.

src/Testcontainers.Azurite/AzuriteBuilder.cs (1)

48-51: Delegating the string constructor to the IImage overload is correct and simplifies initialization

Using : this(new DockerImage(image)) cleanly reuses the IImage-based constructor, avoids duplicated Init().WithImage(...) logic, and keeps behavior centralized without changing the public API surface. This aligns well with the PR’s goal of reducing copy‑paste across builders.

src/Testcontainers.FakeGcsServer/FakeGcsServerBuilder.cs (1)

33-36: String constructor delegation to DockerImage looks correct and keeps image wiring centralized

Routing FakeGcsServerBuilder(string image) through this(new DockerImage(image)) aligns the string-based path with the IImage constructor, removing duplicated initialization while preserving the public surface. This keeps all image configuration logic in one place (FakeGcsServerBuilder(IImage image)), which will simplify future changes to image handling and reduce drift between overloads.

src/Testcontainers.Oracle/OracleBuilder.cs (1)

38-41: String-based constructor delegation to IImage path looks correct

Routing OracleBuilder(string image) through new DockerImage(image) and into the OracleBuilder(IImage image) overload cleanly centralizes image initialization in a single path (Init().WithImage(image)), with no change to the public API or observable behavior. This aligns with the PR’s stated goal and matches the existing configuration flow in the IImage ctor.

src/Testcontainers.RavenDb/RavenDbBuilder.cs (1)

31-34: Constructor delegation to IImage overload looks correct and aligns with refactor goal

Routing RavenDbBuilder(string image) through this(new DockerImage(image)) cleanly reuses the IImage-based constructor, centralizing image initialization (Init().WithImage(image)) and removing duplication. The constructor chain (stringIImageRavenDbConfiguration) is clear and non-recursive, and the obsolete parameterless ctor now also benefits from the unified path.

src/Testcontainers.InfluxDb/InfluxDbBuilder.cs (1)

39-42: String constructor delegation to DockerImage/IImage path looks correct

Delegating InfluxDbBuilder(string image) to this(new DockerImage(image)) cleanly reuses the IImage-based constructor, removes duplicated Init().WithImage(image) wiring, and keeps the public API unchanged. The initialization flow remains centralized in the IImage overload, which is preferable for future changes to image handling.

src/Testcontainers.Keycloak/KeycloakBuilder.cs (1)

37-40: String ctor delegation to DockerImage looks good

Routing the string-based constructor through this(new DockerImage(image)) cleanly aligns it with the IImage-based path and centralizes image parsing/validation, without changing the public API surface. This matches the broader refactor pattern and keeps initialization logic in one place.

src/Testcontainers.Mosquitto/MosquittoBuilder.cs (1)

41-44: Constructor delegation to IImage overload looks correct

Routing MosquittoBuilder(string image) through new DockerImage(image) into the IImage-based constructor cleanly removes duplication while preserving the existing initialization path (Init().WithImage(image) in the IImage ctor). No behavioral or API-surface regressions are apparent here.

src/Testcontainers.Kafka/KafkaBuilder.cs (1)

47-50: Constructor delegation to IImage is clean and preserves behavior

Routing KafkaBuilder(string image) through this(new DockerImage(image)) is a good simplification: it removes duplicated initialization logic and ensures the string- and IImage-based constructors share the same configuration path. No functional issues spotted here.

src/Testcontainers.MongoDb/MongoDbBuilder.cs (1)

39-42: Good ctor delegation, reduces duplication and centralizes image handling

Delegating the string overload to the IImage-based constructor via new DockerImage(image) keeps behavior consistent while removing duplicated Init().WithImage(...) logic and aligning with the other builders’ pattern. No issues spotted here.

src/Testcontainers.Milvus/MilvusBuilder.cs (1)

37-40: LGTM! Constructor delegation reduces code duplication.

The refactoring correctly delegates the string constructor to the IImage constructor by wrapping the image string in a DockerImage instance. This eliminates duplicate initialization code and centralizes image configuration logic in the IImage constructor path. This pattern is consistently applied across 30+ builder files in the codebase.

src/Testcontainers.FirebirdSql/FirebirdSqlBuilder.cs (1)

41-44: LGTM! Clean delegation to IImage constructor.

The refactoring successfully reduces code duplication by delegating to the IImage constructor, which centralizes the image initialization logic. The public API remains unchanged.

src/Testcontainers.ServiceBus/ServiceBusBuilder.cs (1)

37-40: String constructor delegation to IImage ctor looks good

Delegating ServiceBusBuilder(string image) to this(new DockerImage(image)) cleanly centralizes image handling in the IImage-based constructor, removes duplication, and keeps the public API unchanged. The chaining from the obsolete parameterless ctor through this path remains consistent.

src/Testcontainers.ActiveMq/ArtemisBuilder.cs (1)

37-40: String constructor delegation looks correct and simplifies initialization

Routing ArtemisBuilder(string image) through : this(new DockerImage(image)) cleanly reuses the IImage-based constructor, centralizing image wiring and avoiding duplicated Init()/WithImage logic. This is consistent with the PR’s stated pattern and doesn’t introduce new behavior differences for callers of the string overload.

src/Testcontainers.KurrentDb/KurrentDbBuilder.cs (1)

31-34: String-based ctor delegation through DockerImage is clean and consistent

Routing KurrentDbBuilder(string image) through this(new DockerImage(image)) nicely centralizes image setup in the IImage-based constructor, removes duplication, and keeps the public API intact. I don’t see any behavioral regressions given the existing Init().WithImage(image) pattern in the IImage ctor.

src/Testcontainers.BigQuery/BigQueryBuilder.cs (2)

48-52: LGTM! Properly centralizes image configuration logic.

The new IImage constructor correctly centralizes the image setup by:

  1. Creating a fresh BigQueryConfiguration
  2. Applying default settings via Init() (port binding, project ID, wait strategy)
  3. Configuring the Docker image via WithImage(image)
  4. Extracting and assigning the final DockerResourceConfiguration

This eliminates duplication and establishes a single source of truth for image-based initialization.


33-36: LGTM! Clean delegation to IImage constructor.

The refactoring correctly delegates to the new IImage-based constructor, reducing duplication while preserving the public API. The delegation chain is clear: string → DockerImage wrapper → IImage constructor. DockerImage properly implements the IImage interface and is used consistently across the builder pattern.

src/Testcontainers.Weaviate/WeaviateBuilder.cs (1)

30-33: Constructor delegation to IImage via DockerImage is correct and reduces duplication.

The WeaviateBuilder(string image) constructor now cleanly reuses the IImage-based path with new DockerImage(image), keeping the public API unchanged while centralizing image-related initialization in a single constructor.

src/Testcontainers.Couchbase/CouchbaseBuilder.cs (1)

68-95: Constructor delegation to IImage overload looks correct and simplifies initialization

Routing CouchbaseBuilder(string image) through : this(new DockerImage(image)) cleanly centralizes image handling in the IImage-based constructor, removes duplicate Init().WithImage(...) logic, and maintains the existing construction flow (stringIImageCouchbaseConfiguration) without introducing recursion or behavior changes. This aligns well with the broader refactor pattern in the PR.

src/Testcontainers.Papercut/PapercutBuilder.cs (1)

33-36: Clean refactoring that consolidates image initialization logic.

The delegation from the string constructor to the IImage constructor (via new DockerImage(image)) correctly reduces code duplication by centralizing the image setup in one place. The constructor chain is properly implemented: string → IImage → private config → base, with the IImage constructor handling Init().WithImage(image).

src/Testcontainers.Kusto/KustoBuilder.cs (1)

35-37: Delegating the string constructor to IImage looks good.

Routing KustoBuilder(string image) through new DockerImage(image) cleanly centralizes initialization in the IImage-based ctor and reduces duplication, with no change to the public surface or observable behavior in this file.

src/Testcontainers.Typesense/TypesenseBuilder.cs (1)

35-38: String constructor correctly delegates to the IImage-based path

Routing TypesenseBuilder(string image) through this(new DockerImage(image)) aligns it with the IImage constructor, centralizing the Init().WithImage(image) logic and removing duplication without changing the public surface or ctor chain (including the obsolete parameterless ctor). Assuming DockerImage implements IImage as used elsewhere in the library and there are no missing usings for its namespace, this looks functionally equivalent to the previous behavior; re-running the existing Typesense builder tests should be sufficient to validate.

src/Testcontainers.Toxiproxy/ToxiproxyBuilder.cs (2)

35-38: LGTM! Clean delegation pattern.

The string constructor now cleanly delegates to the IImage overload by wrapping the string in DockerImage. This reduces duplication and centralizes image configuration logic.


50-54: Constructor pattern works correctly.

The IImage constructor properly initializes the configuration by:

  1. Delegating to the private constructor with a fresh ToxiproxyConfiguration
  2. Extracting the fully initialized configuration from Init().WithImage(image)

This pattern ensures all default settings (port bindings, wait strategies) are applied along with the specified image.

src/Testcontainers.MariaDb/MariaDbBuilder.cs (1)

37-40: LGTM! Delegation successfully reduces duplication.

The refactoring consolidates image initialization logic by delegating to the IImage constructor instead of duplicating the configuration setup. This achieves the PR's objective of reducing copy-and-paste code while preserving the public API.

DockerImage properly implements IImage and includes robust validation. The string constructor at line 48 delegates through GetDockerImage(image) (which uses MatchImage.Match for parsing), then to the full constructor that validates the repository is not null, empty, or uppercase. This ensures the delegation chain in MariaDbBuilder is safe and preserves all necessary validations.

src/Testcontainers.Minio/MinioBuilder.cs (1)

35-38: Refactoring reduces duplication effectively.

The delegation from the string constructor to the IImage constructor via new DockerImage(image) eliminates duplicate initialization logic while preserving the public API. DockerImage is properly accessible through the global using statement for DotNet.Testcontainers.Images and implements the required IImage interface with a string constructor.

src/Testcontainers.CouchDb/CouchDbBuilder.cs (2)

50-54: Good: Centralized image initialization.

The IImage constructor now serves as the single point for image-based configuration, handling the Init().WithImage(image) logic that was previously duplicated in the string constructor. This improves maintainability and aligns with the DRY principle.


35-38: Constructor delegation pattern is correct and consistent across the codebase.

The string constructor properly delegates to CouchDbBuilder(IImage) via new DockerImage(image), which is the intended design for image initialization. This delegation pattern is consistently used across 60 builders in the codebase, confirming the refactoring successfully eliminates copy-paste code while maintaining equivalent behavior.

src/Testcontainers.MySql/MySqlBuilder.cs (1)

37-40: Clean refactoring that consolidates image initialization.

The delegation to new DockerImage(image) properly consolidates the image initialization logic into the IImage constructor path, reducing duplication. DockerImage correctly implements IImage with a string constructor that parses the image name. The public API remains unchanged, maintaining backward compatibility.

src/Testcontainers.JanusGraph/JanusGraphBuilder.cs (2)

46-50: LGTM! IImage constructor correctly applies defaults via Init().

The constructor properly initializes the configuration by:

  1. Delegating to the private constructor with an empty JanusGraphConfiguration
  2. Overwriting DockerResourceConfiguration with the result of Init().WithImage(image)

This pattern ensures that all default settings from Init() (port binding, environment variables, wait strategy) are consistently applied alongside the provided image. While creating an intermediate configuration is necessary due to constructor ordering constraints, the approach correctly consolidates initialization logic.


31-34: Clean delegation to IImage constructor.

The refactoring correctly delegates to the IImage constructor via new DockerImage(image), eliminating duplicate initialization logic and centralizing image handling. DockerImage(string) is the standard pattern throughout the codebase for string-to-IImage conversion.

src/Testcontainers.Db2/Db2Builder.cs (1)

37-40: LGTM! Clean refactoring that eliminates code duplication.

The delegation to the IImage constructor centralizes the image initialization logic (Init().WithImage(image)), removing duplicate code that was previously in the string constructor. The public API signature is preserved, and the behavior remains identical.

src/Templates/CSharp/Testcontainers.ModuleName/Usings.cs (1)

1-11: Template: global using for DockerImage is appropriate

Adding global using DotNet.Testcontainers.Images; keeps the template self-contained and enables the new DockerImage usage in ModuleNameBuilder without forcing per-file usings. No issues from a correctness or style perspective.

src/Testcontainers.K3s/K3sBuilder.cs (1)

33-36: K3s string constructor delegation looks correct

Routing K3sBuilder(string image) through : this(new DockerImage(image)) cleanly reuses the IImage-based constructor and removes duplicate Init().WithImage(...) logic while preserving behavior. No additional validation or changes needed here.

src/Testcontainers.Redis/RedisBuilder.cs (1)

31-34: Redis string constructor now correctly funnels through IImage path

RedisBuilder(string image) : this(new DockerImage(image)) matches the pattern used elsewhere, centralizing image handling in the IImage constructor and avoiding repeated init code. Semantics remain consistent for callers.

src/Testcontainers.Cassandra/CassandraBuilder.cs (1)

33-36: Cassandra string constructor delegation is consistent and safe

Delegating CassandraBuilder(string image) to new DockerImage(image) and the IImage overload removes copy‑paste initialization while keeping the same configuration flow via Init().WithImage(image). No functional regressions apparent.

src/Testcontainers.CosmosDb/CosmosDbBuilder.cs (1)

33-36: CosmosDb string constructor delegation aligns with new image model

Using : this(new DockerImage(image)) for CosmosDbBuilder(string image) correctly reuses the IImage constructor and centralizes the image wiring there. Behavior for consumers passing an image string should remain unchanged apart from going through the DockerImage abstraction.

src/Testcontainers.Playwright/PlaywrightBuilder.cs (1)

33-36: Playwright string constructor delegation looks good

PlaywrightBuilder(string image) : this(new DockerImage(image)) cleanly reuses the existing IImage-based constructor and removes duplicate setup logic. This keeps the public API intact while simplifying maintenance.

src/Testcontainers.OpenSearch/OpenSearchBuilder.cs (1)

39-42: OpenSearch string constructor now properly reuses IImage flow

Delegating OpenSearchBuilder(string image) to : this(new DockerImage(image)) is consistent with the rest of the PR and ensures that all image handling (including the version-based behavior in Build()) goes through a single IImage-based code path. No issues spotted.

src/Testcontainers.Elasticsearch/ElasticsearchBuilder.cs (1)

45-48: Clean refactoring that centralizes image initialization.

The string constructor now properly delegates to the IImage constructor via DockerImage, eliminating duplicate initialization logic. The constructor chain is correct: stringIImageConfiguration.

src/Testcontainers.Consul/ConsulBuilder.cs (1)

33-36: LGTM!

Consistent with the established pattern—string constructor delegates to the IImage constructor, centralizing the initialization logic.

src/Testcontainers.ArangoDb/ArangoDbBuilder.cs (1)

35-38: LGTM!

The refactoring correctly delegates the string constructor to the IImage path, maintaining consistency across the codebase.

src/Testcontainers.ClickHouse/ClickHouseBuilder.cs (1)

39-42: LGTM!

String constructor correctly delegates to the IImage constructor via DockerImage.

src/Testcontainers.WebDriver/WebDriverBuilder.cs (1)

59-62: LGTM!

Refactoring correctly centralizes image initialization in the IImage constructor path.

src/Testcontainers.Grafana/GrafanaBuilder.cs (1)

35-38: LGTM!

Consistent delegation pattern applied correctly.

src/Testcontainers.MsSql/MsSqlBuilder.cs (1)

37-40: LGTM!

String constructor correctly delegates to the IImage path, reducing duplication.

src/Testcontainers.PostgreSql/PostgreSqlBuilder.cs (1)

37-40: LGTM!

String constructor correctly delegates to the IImage constructor, completing the consistent refactoring pattern across all builder classes.

src/Testcontainers.Firestore/FirestoreBuilder.cs (1)

31-34: String constructor delegation looks correct

Routing FirestoreBuilder(string image) through new DockerImage(image) to the IImage-based constructor cleanly centralizes image handling without changing observable behavior.

src/Testcontainers/Builders/ContainerBuilder.cs (1)

52-55: Consistent delegation through DockerImage

ContainerBuilder(string image) now correctly delegates to the IImage-based path via new DockerImage(image), aligning with other builders and keeping initialization logic in one place.

src/Testcontainers.LocalStack/LocalStackBuilder.cs (1)

31-34: Delegation pattern is sound

LocalStackBuilder(string image) delegating to new DockerImage(image) correctly reuses the IImage-based initialization path, reducing duplication and preserving behavior.

src/Testcontainers.Redpanda/RedpandaBuilder.cs (1)

35-54: Centralizing image handling via IImage overload is sound; no ambiguous null calls found

Routing the string overload through this(new DockerImage(image)) and doing the actual initialization in the IImage-based ctor is a clean refactor and aligns with the broader PR pattern. It removes duplicated Init().WithImage(...) wiring while keeping existing public signatures intact.

The theoretical concern about null-argument ambiguity between string and IImage overloads is valid, but codebase inspection shows no such calls exist. All constructor usages are explicit: either passing configuration objects, or passing explicit IImage instances (e.g., from TestSession.GetImageFromDockerfile()).

src/Testcontainers.LowkeyVault/LowkeyVaultBuilder.cs (1)

33-36: LGTM—clean delegation to IImage constructor that reduces code duplication.

The refactoring correctly centralizes image configuration through the DockerImage wrapper, routing initialization through the IImage constructor path where Init().WithImage(image) is called. This eliminates duplication while maintaining the same public API. The property pattern using { get; } is valid C# for constructor initialization of backing fields. Tests confirm the change works correctly.

src/Testcontainers.Neo4j/Neo4jBuilder.cs (1)

33-36: Good refactoring to consolidate constructor logic.

Delegating the string-based constructor through DockerImage(image) to the IImage constructor path eliminates code duplication and centralizes image configuration. The public API signature remains unchanged and behavior is preserved since Init().WithImage() is still invoked in the IImage constructor. Edge cases (null, empty, or malformed image strings) are properly validated by the DockerImage constructor.

@HofmeisterAn HofmeisterAn merged commit dc28b26 into develop Dec 7, 2025
81 checks passed
@HofmeisterAn HofmeisterAn deleted the feature/delegate-to-ctor branch December 7, 2025 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore A change that doesn't impact the existing functionality, e.g. internal refactorings or cleanups

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants