xUnit’s TestContainers library includes a fixture for simplifying writing integration tests, however it does not work well with reusable containers since TestContainers doesn’t support creating containers idempotently across parallel processes.
Why Reuse?
There are a couple of common strategies when orchestrating integration dependencies when writing integration tests:
- In-memory orchestration
- Real dependencies
- Third-party emulators
TestContainers enable the two latter while simplifying orchestration, but the downside of these strategies compared to the first is start and stop latency, which may become a serious problem as the number of tests increase. Enter Reuse.
Lack of Idempotency
TestContainers uses the create container endpoint from the Docker API to create a new container. If Reuse is enabled, it first checks if their is a container matching a hash representing the labels of the current test container, if there is, it reuses it, otherwise it creates a new container using a random pseudo name which is not deterministic and hence makes this process non-idempotent. This works fine when running tests in a single, sequential process, but will eventually fail if using parallel processes or a process that run tests in parallel without synchronization.
An example is NCrunch, which by default parallelize test execution to multiple processes.
TestContainers will fail because it will eventually create more than one container with the same hash which will cause the framework to fail on the next execution, as it doesn’t support multiple containers with the same hash, nor does it align with the purpose of reusability.
TestContainers.Xunit.Reusable
TestContainers.Xunit.Reusable is a drop-in replacement for Testcontainers.XunitV3 that supports idempotency by simply using the reuse hash as the name of the reusable container. It implements optimistic concurrency, meaning if a process fails creating a reusable container due to conflict, it will reuse it as another parallel process managed to create the container first.
Simply replace <PackageReference Include="Testcontainers.XunitV3" Version="x.y.z" /> with <PackageReference Include="Reusable.XunitV3.TestContainers" Version="a.b.c" />. Enable reusability for a ContainerFixture by overriding the Reuse property or by setting the TESTCONTAINERS_REUSE_ENABLE environment variable to ‘true’.

Not sure what Kaka is, but yay, AI! 😀
Leave a Comment



