File: README.md
Testcontainers
Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
[Read the documentation here](https://java.testcontainers.org)
License
See LICENSE.
Copyright
Copyright (c) 2015 - 2021 Richard North and other authors.
MS SQL Server module is (c) 2017 - 2021 G DATA Software AG and other authors.
Hashicorp Vault module is (c) 2017 - 2021 Capital One Services, LLC and other authors.
See contributors for all contributors.
File: core/testlib/README.md
This directory contains a synthetic JAR (fakejar.jar) that is needed for org.testcontainers.utility.MountableFileTest.
The create_fakejar.sh script may be used to recreate it.
File: docs/features/advanced_options.md
Advanced options
Container labels
To add a custom label to the container, use withLabel:
Adding a single label inside_block:single_label
Additionally, multiple labels may be applied together from a map:
Adding multiple labels inside_block:multiple_labels
Image Pull Policy
By default, the container image is retrieved from the local Docker images cache.
This works well when running against a specific version, but for images with a static tag (i.e. 'latest') this may lead to a newer version not being pulled.
It is possible to specify an Image Pull Policy to determine at runtime whether an image should be pulled or not:
Setting image pull policy inside_block:built_in_image_pull_policy
... or providing a function:
Custom image pull policy inside_block:custom_image_pull_policy
You can also configure Testcontainers to use your custom implementation by using pull.policy
=== "src/test/resources/testcontainers.properties"
text pull.policy=com.mycompany.testcontainers.ExampleImagePullPolicy
You can also use the provided implementation to always pull images
=== "src/test/resources/testcontainers.properties"
text pull.policy=org.testcontainers.images.AlwaysPullPolicy
Please see the documentation on configuration mechanisms for more information.
Customizing the container
Using docker-java
It is possible to use the docker-java API directly to customize containers before creation. This is useful if there is a need to use advanced Docker features that are not exposed by the Testcontainers API. Any customizations you make using withCreateContainerCmdModifier will be applied on top of the container definition that Testcontainers creates, but before it is created.
For example, this can be used to change the container hostname:
Using modifier to change hostname inside_block:hostname
... or modify container memory (see this if it does not appear to work):
Using modifier to change memory limits inside_block:memory
!!! note
It is recommended to use this sparingly, and follow changes to the docker-java API if you choose to use this.
It is typically quite stable, though.
For what is possible, consult the docker-java CreateContainerCmd source code.
Using CreateContainerCmdModifier
Testcontainers provides a CreateContainerCmdModifier to customize docker-java CreateContainerCmd
via Service Provider Interface (SPI) mechanism.
CreateContainerCmd example implementation
The previous implementation should be registered in META-INF/services/org.testcontainers.core.CreateContainerCmdModifier file.
!!! warning
CreateContainerCmdModifier implementation will apply to all containers created by Testcontainers.
Parallel Container Startup
Usually, containers are started sequentially when more than one container is used.
Using Startables.deepStart(container1, container2, ...).join() will start all containers in parallel.
This can be advantageous to reduce the impact of the container startup overhead.
File: docs/features/commands.md
Executing commands
Container startup command
By default the container will execute whatever command is specified in the image's Dockerfile. To override this, and specify a different command, use withCommand. For example:
Specifying a startup command inside_block:startupCommand
Executing a command
Your test can execute a command inside a running container, similar to a docker exec call:
Executing a command inside a running container inside_block:standaloneExec
This can be useful for software that has a command line administration tool. You can also get the output (stdout/stderr) and exit code from the command - for example:
Executing a command inside a running container and reading the result inside_block:execReadingStdout
Environment variables
To add environment variables to the container, use withEnv:
new GenericContainer(...)
.withEnv("API_TOKEN", "foo")File: docs/features/configuration.md
Custom configuration
You can override some default properties if your environment requires that.
Configuration locations
The configuration will be loaded from multiple locations. Properties are considered in the following order:
- Environment variables
.testcontainers.propertiesin user's home folder. Example locations:
Linux:/home/myuser/.testcontainers.properties
Windows:C:/Users/myuser/.testcontainers.properties
macOS:/Users/myuser/.testcontainers.propertiestestcontainers.propertieson the classpath.
Note that when using environment variables, configuration property names should be set in upper
case with underscore separators, preceded by TESTCONTAINERS_ - e.g. checks.disable becomesTESTCONTAINERS_CHECKS_DISABLE.
The classpath testcontainers.properties file may exist within the local codebase (e.g. within the src/test/resources directory) or within library dependencies that you may have.
Any such configuration files will have their contents merged.
If any keys conflict, the value will be taken on the basis of the first value found in:
- 'local' classpath (i.e. where the URL of the file on the classpath begins with
file:), then - other classpath locations (i.e. JAR files) - considered in alphabetical order of path to provide deterministic ordering.
Disabling the startup checks
checks.disable = [true|false]
Before running any containers Testcontainers will perform a set of startup checks to ensure that your environment is configured correctly. Usually they look like this:
โน๏ธ Checking the system...
โ Docker version should be at least 1.6.0
โ File should be mountable
โ A port exposed by a docker container should be accessibleIt takes a couple of seconds, but if you want to speed up your tests, you can disable the checks once you have everything configured. Add checks.disable=true to your $HOME/.testcontainers.properties to completely disable them.
Customizing images
!!! note
This approach is discouraged and deprecated, but is documented for completeness.
Overriding individual image names via configuration may be removed in 2021.
See Image Name Substitution for other strategies for substituting image names to pull from other registries.
Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others.
Some companies disallow the usage of Docker Hub, but you can override *.image properties with your own images from your private registry to workaround that.
ryuk.container.image = testcontainers/ryuk:0.3.3
Performs fail-safe cleanup of containers, and always required (unless Ryuk is disabled)
tinyimage.container.image = alpine:3.17
Used to check whether images can be pulled at startup, and always required (unless startup checks are disabled)
sshd.container.image = testcontainers/sshd:1.4.0
Required if exposing host ports to containers
vncrecorder.container.image = testcontainers/vnc-recorder:1.3.0
Used by VNC recorder in Testcontainers' Selenium integration
socat.container.image = alpine/socat
compose.container.image = docker/compose:1.8.0
Required if using Docker Compose
kafka.container.image = confluentinc/cp-kafka
Used by KafkaContainer
localstack.container.image = localstack/localstack
Used by LocalStack
pulsar.container.image = apachepulsar/pulsar:2.2.0
Used by Apache Pulsar
Customizing Ryuk resource reaper
ryuk.container.image = testcontainers/ryuk:0.3.3
The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown
ryuk.container.privileged = true
In some environments ryuk must be started in privileged mode to work properly (--privileged flag)
Disabling Ryuk
Ryuk must be started as a privileged container.
If your environment already implements automatic cleanup of containers after the execution,
but does not allow starting privileged containers, you can turn off the Ryuk container by settingTESTCONTAINERS_RYUK_DISABLED environment variable to true.
!!!tip
Note that Testcontainers will continue doing the cleanup at JVM's shutdown, unless you kill -9 your JVM process.
Customizing image pull behaviour
pull.timeout = 120
By default Testcontainers will timeout if pull takes more than this duration (in seconds)
pull.pause.timeout = 30
By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds).
Customizing client ping behaviour
client.ping.timeout = 10
Specifies for how long Testcontainers will try to connect to the Docker client to obtain valid info about the client before giving up and trying next strategy, if applicable (in seconds).
Customizing Docker host detection
Testcontainers will attempt to detect the Docker environment and configure everything to work automatically.
However, sometimes customization is required. Testcontainers will respect the following environment variables:
DOCKER_HOST = unix:///var/run/docker.sock
See Docker environment variablesTESTCONTAINERS_DOCKER_SOCKET_OVERRIDE
Path to Docker's socket. Used by Ryuk, Docker Compose, and a few other containers that need to perform Docker actions.
Example:/var/run/docker-alt.sockTESTCONTAINERS_HOST_OVERRIDE
Docker's host on which ports are exposed.
Example:docker.svc.local
For advanced users, the Docker host connection can be configured via configuration in ~/.testcontainers.properties.
Note that these settings require use of the EnvironmentAndSystemPropertyClientProviderStrategy. The example below
illustrates usage:
docker.client.strategy=org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy
docker.host=tcp\://my.docker.host\:1234 # Equivalent to the DOCKER_HOST environment variable. Colons should be escaped.
docker.tls.verify=1 # Equivalent to the DOCKER_TLS_VERIFY environment variable
docker.cert.path=/some/path # Equivalent to the DOCKER_CERT_PATH environment variableIn addition, you can deactivate this behaviour by specifying:
dockerconfig.source=autoIgnoringUserProperties # 'auto' by defaultFile: docs/features/container_logs.md
Accessing container logs
It is possible to capture container output using:
- the
getLogs()method, which simply returns aStringsnapshot of a container's entire log output - the
followOutput()method. This method accepts a Consumer and (optionally)
a varargs list stating which of STDOUT, STDERR, or both, should be followed. If not specified, both will be followed.
At present, container output will always begin from the time of container creation.
Reading all logs (from startup time to present)
getLogs() is the simplest mechanism for accessing container logs, and can be used as follows:
Accessing all output (stdout and stderr) inside_block:docsGetAllLogs
Accessing just stdout inside_block:docsGetStdOut
Accessing just stderr inside_block:docsGetStdErr
Streaming logs
Testcontainers includes some out-of-the-box Consumer implementations that can be used with the streaming followOutput() model; examples follow.
Streaming container output to an SLF4J logger
Given an existing SLF4J logger instance named LOGGER:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER);
container.followOutput(logConsumer);By default both standard out and standard error will both be emitted at INFO level.
Standard error may be emitted at ERROR level, if desired:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withSeparateOutputStreams();The Mapped Diagnostic Context (MDC) for emitted messages may be configured using the withMdc(...) option:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc("key", "value");or using an existing map of key-value pairs:
Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER).withMdc(map);Capturing container output as a String
To stream logs live or customize the decoding, ToStringConsumer may be used:
ToStringConsumer toStringConsumer = new ToStringConsumer();
container.followOutput(toStringConsumer, OutputType.STDOUT);
String utf8String = toStringConsumer.toUtf8String();
// Or if the container output is not UTF-8
String otherString = toStringConsumer.toString(CharSet.forName("ISO-8859-1"));Waiting for container output to contain expected content
WaitingConsumer will block until a frame of container output (usually a line) matches a provided predicate.
A timeout may be specified, as shown in this example.
WaitingConsumer consumer = new WaitingConsumer();
container.followOutput(consumer, STDOUT);
consumer.waitUntil(frame ->
frame.getUtf8String().contains("STARTED"), 30, TimeUnit.SECONDS);Additionally, as the Java 8 Consumer functional interface is used, Consumers may be composed together. This is
useful, for example, to capture all the container output but only when a matching string has been found. e.g.:
WaitingConsumer waitingConsumer = new WaitingConsumer();
ToStringConsumer toStringConsumer = new ToStringConsumer();
Consumer<OutputFrame> composedConsumer = toStringConsumer.andThen(waitingConsumer);
container.followOutput(composedConsumer);
waitingConsumer.waitUntil(frame ->
frame.getUtf8String().contains("STARTED"), 30, TimeUnit.SECONDS);
String utf8String = toStringConsumer.toUtf8String();File: docs/features/creating_container.md
Creating a container
Creating a generic container based on an image
Testcontainers' generic container support offers the most flexibility, and makes it easy to use virtually any container
images as temporary test dependencies. For example, if you might use it to test interactions with:
- NoSQL databases or other data stores (e.g. redis, elasticsearch, mongo)
- Web servers/proxies (e.g. nginx, apache)
- Log services (e.g. logstash, kibana)
- Other services developed by your team/organization which are already dockerized
With a generic container, you set the container image using a parameter to the rule constructor, e.g.:
new GenericContainer(DockerImageName.parse("jboss/wildfly:9.0.1.Final"))Specifying an image
Many Container classes in Testcontainers have historically supported:
- a no-args constructor - for example
new GenericContainer()andnew ElasticsearchContainer(). With these constructors, Testcontainers has traditionally used a default image name (including a fixed image tag/version). This has caused a conflict between the need to keep the defaults sane (i.e. up to date) and the need to avoid silently upgrading these dependencies along with new versions of Testcontainers. - a single string-argument constructor, which has taken either a version or an image name as a String. This has caused some ambiguity and confusion.
Since v1.15.0, both of these constructor types have been deprecated, for the reasons given above.
Instead, it is highly recommended that all containers be constructed using a constructor that accepts a DockerImageName object.
The DockerImageName class is an unambiguous reference to a docker image.
It is suggested that developers treat DockerImageNames as you would any other potentially-constant value - consider defining a constant in your test codebase that matches the production version of the dependency you are using.
Examples
A generic container rule can be used with any public docker image; for example:
Creating a Redis container inside_block:container
The container, as @Container, will be started before any tests in the class run, and will be destroyed after all
tests have run.
File: docs/features/creating_images.md
Creating images on-the-fly
Overview
In situations where there is no pre-existing Docker image, Testcontainers can create a new temporary image on-the-fly
from a Dockerfile. For example, when the component under test is the Docker image itself, or when an existing base
image needs to be customized for specific test(s).
Simply pass a configured instance of ImageFromDockerfile as a constructor parameter to GenericContainer.
Testcontainers will docker build a temporary container image, and will use it when creating the container.
Dockerfile from String, file or classpath resource
ImageFromDockerfile accepts arbitrary files, strings or classpath resources to be used as files in the build context.
At least one of these needs to be a Dockerfile.
GenericContainer container = new GenericContainer(
new ImageFromDockerfile()
.withFileFromString("folder/someFile.txt", "hello")
.withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt")
.withFileFromClasspath("Dockerfile", "mappable-dockerfile/Dockerfile"))The following methods may be used to provide the Dockerfile and any other required build context files:
withFileFromString(buildContextPath, content)withFileFromClasspath(buildContextPath, classpathPath)withFileFromPath(buildContextPath, filesystemPath)withFileFromFile(buildContextPath, filesystemFile)
!!! info
In older versions of Testcontainers (before 1.3.0) it was necessary to explicitly declare each file that needed to
be present in the Docker build context.
This can be replaced with the following syntax:
[Passing an entire directory of files to the Dockerfile build context](../../core/src/test/java/org/testcontainers/images/builder/DockerfileBuildTest.java) inside_block:docsShowRecursiveFileInclusion
Where `RESOURCE_PATH` is the path to a directory containing a `Dockerfile` and any files that it needs to refer to.
Doing this is equivalent to `docker build RESOURCE_PATH` on the command line.
To mimic `docker build .`, `RESOURCE_PATH` would simply be set to `.` as well.Dockerfile DSL
If a static Dockerfile is not sufficient (e.g. your test needs to cover many variations that are best generated
programmatically), there is a DSL available to allow Dockerfiles to be defined in code. e.g.:
new GenericContainer(
new ImageFromDockerfile()
.withDockerfileFromBuilder(builder ->
builder
.from("alpine:3.17")
.run("apk add --update nginx")
.cmd("nginx", "-g", "daemon off;")
.build()))
.withExposedPorts(80);See ParameterizedDockerfileContainerTest for a very basic example of using this in conjunction with JUnit
parameterized testing.
Automatic deletion
Temporary container images will be automatically removed when the test JVM shuts down. If this is not desired and
the image should be retained between tests, pass a stable image name and false flag to the ImageFromDockerfile
constructor.
Retaining the image between tests will use Docker's image cache to accelerate subsequent test runs.
By default the no-args constructor will use an image name of the form testcontainers/ + random string:
public ImageFromDockerfile()public ImageFromDockerfile(String dockerImageName)public ImageFromDockerfile(String dockerImageName, boolean deleteOnExit)
Alternative Dockerfiles
Normally Docker will automatically build an image from any /Dockerfile that it finds in the root of the build context.
To override this behaviour, use .withDockerfilePath("./Name-Of-Other-Dockerfile").
Build Args
Build Args may be used to allow lightweight parameterization.
To specify build args, use .withBuildArg("varname", "value") or provide a Map of args using .withBuildArgs(map).
File: docs/features/files.md
Files and volumes
Copying files
Files can be copied into the container before startup, or can be copied from the container after the container has started.
!!! note
This is the recommended approach for portability cross-docker environments.
Copying to a container before startup
Copying files using MountableFile inside_block:copyToContainer
Using Transferable, file content will be placed in the specified location.
Copying files using Transferable inside_block:transferableFile
Setting file mode is also possible.
Copying files using Transferable with file mode inside_block:transferableWithFileMode
Copying a file from a running container
Copying files from a container inside_block:copyFileFromContainer
File: docs/features/image_name_substitution.md
Image name substitution
Testcontainers supports automatic substitution of Docker image names.
This allows replacement of an image name specified in test code with an alternative name - for example, to replace the
name of a Docker Hub image dependency with an alternative hosted on a private image registry.
This is advisable to avoid Docker Hub rate limiting, and some companies will prefer this for policy reasons.
This page describes four approaches for image name substitution:
- Manual substitution - not relying upon an automated approach
- Using an Image Name Substitutor:
It is assumed that you have already set up a private registry hosting all the Docker images your build requires.
Manual substitution
Consider this if:
- You use only a few images and updating code is not a chore
- All developers and CI machines in your organisation have access to a common registry server
- You also use one of the automated mechanisms to substitute the images that Testcontainers itself requires
This approach simply entails modifying test code manually, e.g. changing:
For example, you may have a test that uses the mysql container image from Docker Hub:
Direct Docker Hub image name inside_block:directDockerHubReference
to:
Private registry image name inside_block:hardcodedMirror
Automatically modifying Docker Hub image names
Testcontainers can be configured to modify Docker Hub image names on the fly to apply a prefix string.
Consider this if:
- Developers and CI machines need to use different image names. For example, developers are able to pull images from Docker Hub, but CI machines need to pull from a private registry
- Your private registry has copies of images from Docker Hub where the names are predictable, and just adding a prefix is enough.
For example,registry.mycompany.com/mirror/mysql:8.0.36can be derived from the original Docker Hub image name (mysql:8.0.36) with a consistent prefix string:registry.mycompany.com/mirror/
In this case, image name references in code are unchanged.
i.e. you would leave as-is:
Unchanged direct Docker Hub image name inside_block:directDockerHubReference
You can then configure Testcontainers to apply the prefix registry.mycompany.com/mirror/ to every image that it tries to pull from Docker Hub.
This can be done in one of two ways:
- Setting environment variables
TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX=registry.mycompany.com/mirror/ - Via config file, setting
hub.image.name.prefixin either:- the
~/.testcontainers.propertiesfile in your user home directory, or - a file named
testcontainers.propertieson the classpath
- the
Testcontainers will automatically apply the prefix to every image that it pulls from Docker Hub - please verify that all the required images exist in your registry.
Testcontainers will not apply the prefix to:
- non-Hub image names (e.g. where another registry is set)
- Docker Hub image names where the hub registry is explicitly part of the name (i.e. anything with a
docker.ioorregistry.hub.docker.comhost part)
Developing a custom function for transforming image names on the fly
Consider this if:
- You have complex rules about which private registry images should be used as substitutes, e.g.:
- non-deterministic mapping of names meaning that a name prefix cannot be used
- rules depending upon developer identity or location
- or you wish to add audit logging of images used in the build
- or you wish to prevent accidental usage of images that are not on an approved list
In this case, image name references in code are unchanged.
i.e. you would leave as-is:
Unchanged direct Docker Hub image name inside_block:directDockerHubReference
You can implement a custom image name substitutor by:
- subclassing
org.testcontainers.utility.ImageNameSubstitutor - configuring Testcontainers to use your custom implementation
The following is an example image substitutor implementation:
Example Image Substitutor block:ExampleImageNameSubstitutor
Testcontainers can be configured to find it at runtime via configuration.
To do this, create or modify a file on the classpath named testcontainers.properties.
For example:
=== "src/test/resources/testcontainers.properties"
text image.substitutor=com.mycompany.testcontainers.ExampleImageNameSubstitutor
Note that it is also possible to provide this same configuration property:
- in a
testcontainers.propertiesfile at the root of a library JAR file (useful if you wish to distribute a drop-in image substitutor JAR within an organization) - in a properties file in the user's home directory (
~/.testcontainers.properties; note the leading.) - or as an environment variable (e.g.
TESTCONTAINERS_IMAGE_SUBSTITUTOR=com.mycompany.testcontainers.ExampleImageNameSubstitutor).
Please see the documentation on configuration mechanisms for more information.
Also, you can use the ServiceLoader mechanism to provide the fully qualified class name of the ImageNameSubstitutor implementation:
=== "src/test/resources/META-INF/services/org.testcontainers.utility.ImageNameSubstitutor"
text com.mycompany.testcontainers.ExampleImageNameSubstitutor
Overriding image names individually in configuration
!!! note
This approach is discouraged and deprecated, but is documented for completeness.
Please consider one of the other approaches outlined in this page instead.
Overriding individual image names via configuration may be removed in the future.
Consider this if:
- You have many references to image names in code and changing them is impractical, and
- None of the other options are practical for you
In this case, image name references in code are left unchanged.
i.e. you would leave as-is:
Unchanged direct Docker Hub image name inside_block:directDockerHubReference
You can force Testcontainers to substitute in a different image using a configuration file, which allows some (but not all) container names to be substituted.