Join Us

Your Name:(required)

Your Password:(required)

Join Us

Your Name:(required)

Your Email:(required)

Your Message :

0/2000

Getting Started

Author: Geoff

Apr. 29, 2024

8 0

Tags: Measurement & Analysis Instruments

Getting Started

What is Testcontainers?

Please visit our website for more information on this topic.

Testcontainers is a library that provides easy and lightweight APIs for bootstrapping local development and test dependencies with real services wrapped in Docker containers. Using Testcontainers, you can write tests that depend on the same services you use in production without mocks or in-memory services.

What problems does Testcontainers solve?

Cloud-native infrastructure and microservices have taken control away from developers and made it painful to work locally. Let’s say you’re a developer working on “My Service”, within the following architecture:

While you own only My Service and its datastore (in green), you have several downstream dependencies (in blue) that you need for local development and integration testing. This brings the following challenges:

  • Before running tests, you must ensure that the infrastructure is up and running and is pre-configured in a desired state.
  • If the resources (database, message broker, etc) are shared across multiple users or CI pipelines, then the test results are non-deterministic because of the possibility of data corruption and configuration drift.

One way to sidestep these challenges is by relying on in-memory databases, embedded services, mocks, and other fake replicas of the production dependencies. However, these approaches bring their own problems (e.g. In-memory services may not have all the features of your production service and behave slightly differently).

Testcontainers solves these problems by running your application dependencies such as databases, message brokers, etc. in Docker containers and helps executing reliable and repeatable tests by talking to those real services and providing a programmatic API for your test code.

In the previous example, you could freely develop and test “My Service” against real dependencies by provisioning them with Testcontainers, directly from your code:

Benefits of using Testcontainers:

  • On-demand isolated infrastructure provisioning: You don’t need to have a pre-provisioned integration testing infrastructure. Testcontainers will provide the required services before running your tests. There will be no test data pollution, even when multiple build pipelines run in parallel because each pipeline runs with an isolated set of services.

  • Consistent experience on both local and CI environments: You can run your integration tests right from your IDE, just like you run unit tests. No need to push your changes and wait for the CI pipeline to complete.

  • Reliable test setup using wait strategies: Docker containers need to be started and fully initialized before using them in your tests. The Testcontainers library offers several out-of-the-box wait strategies implementations to make sure the containers (and the application within) are fully initialized. Testcontainers modules already implement the relevant wait strategies for a given technology, and you can always implement your own or create a composite strategy if needed.

  • Advanced networking capabilities: Testcontainers libraries map the container’s ports onto random ports available on the host machine so that your tests connect reliably to those services. You can even create a (Docker) network and connect multiple containers together so that they talk to each other via static Docker network aliases.

  • Automatic clean up: The Testcontainers library takes care of removing any created resources (containers, volumes, networks etc.) automatically after the test execution is complete by using the Ryuk sidecar container. While starting the required containers, Testcontainers attaches a set of labels to the created resources (containers, volumes, networks etc) and Ryuk automatically performs resource clean up by matching those labels. This works reliably even when the test process exits abnormally (e.g. sending a SIGKILL).

Differences with Docker and Docker Compose

Docker and Docker Compose can also be used directly for spinning up dependencies that are needed for tests, but this approach has downsides. Creating reliable and fully-initialized service dependencies using raw Docker commands or using Docker Compose requires good knowledge of Docker internals and how to best run specific technologies in a container. For example, creating a dynamic “integration testing environment” by directly using Docker commands or docker-compose may result in port conflicts, containers not being fully initialized or ready for interactions when the tests start, etc. Testcontainers libraries leverage the full power of Docker containers under the hood and expose them to developers via idiomatic APIs.

Supported languages and prerequisites

Testcontainers provide support for the most popular languages and platforms including Java, .NET, Go, NodeJS, Python, Rust and Haskell.

To run Testcontainers-based tests, you need a Docker-API compatible container runtime, such as using Testcontainers Cloud or installing Docker locally. The following container runtime environments are officially supported:

For more extensive information on supported container runtime environments, as well as known limitations of alternative container runtime environments, please refer to this page.

Testcontainers workflow

You can use Testcontainers with any testing library you are already familiar with. A typical Testcontainers-based integration test works as follows:

  • Before Test execution: Start your required services (databases, messaging systems etc.) as Docker containers using the Testcontainers API. Once the required containers start, configure or update your application configuration to use these containerized services and optionally initialize data needed for the test.

  • During Test execution: Your tests run using these containerized services.

  • After Test execution: Testcontainers takes care of destroying containers irrespective of whether tests are executed successfully or there were any failures.

What technologies can I test with?

You can use Testcontainers to run tests with any Dockerized software. Testcontainers can spin up a container from any existing Docker image, a Dockerfile, or even from a Docker Compose file.

GenericContainer abstraction

Testcontainers provides a programmatic abstraction called GenericContainer representing a Docker container. You can use GenericContainer to start a Docker container, get any container information such as hostname (the host under which the mapped ports are reachable), mapped ports, and stop the container.

For example, you can use GenericContainer from Testcontainers for Java as follows:

GenericContainer container = new GenericContainer("postgres:15")
        .withExposedPorts(5432)
        .waitingFor(new LogMessageWaitStrategy()
            .withRegEx(".*database system is ready to accept connections.*\\s")
            .withTimes(2)
            .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)));
container.start();
var username = "test";
var password = "test";
var jdbcUrl = "jdbc:postgresql://" + container.getHost() + ":" + container.getMappedPort(5432) + "/test";
//perform db operations
container.stop();

The GenericContainer API is available for other supported languages as well.

Testcontainers modules

Testcontainers provides modules for a wide range of commonly used infrastructure dependencies including relational databases, NoSQL datastores, search engines, message brokers, etc. See https://testcontainers.com/modules/ for a complete list.

Technology-specific modules are a higher-level abstraction on top of GenericContainer which help configure and run these technologies without any boilerplate, and make it easy to access their relevant parameters.

For example, you can use the Testcontainers postgres module’s PostgreSQLContainer instead of GenericContainer as follows:

PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:15");
postgres.start();
var username = postgres.getUsername();
var password = postgres.getPassword();
var jdbcUrl = postgres.getJdbcUrl();
//perform db operations
postgres.stop();

Using modules makes it much simpler to interact with the technology by providing convenient helper methods such as getJdbcUrl(). Testcontainers modules also take care of implementing technology specific port mapping, appropriate wait strategies, etc.

You can get hands-on experience by working through task-oriented guides available at https://testcontainers.com/guides/. Finally, you should take a look at all the available Testcontainers modules at https://testcontainers.com/modules/ for ideas on how to migrate your existing test suites to Testcontainers.

Happy testing with Testcontainers!

Testcontainers for Java

Testcontainers for Java

Not using Java? Here are other supported languages!

About Testcontainers for Java

Testcontainers for Java 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.

Testcontainers make the following kinds of tests easier:

  • Data access layer integration tests: use a containerized instance of a MySQL, PostgreSQL or Oracle database to test your data access layer code for complete compatibility, but without requiring complex setup on developers' machines and safe in the knowledge that your tests will always start with a known DB state. Any other database type that can be containerized can also be used.
  • Application integration tests: for running your application in a short-lived test mode with dependencies, such as databases, message queues or web servers.
  • UI/Acceptance tests: use containerized web browsers, compatible with Selenium, for conducting automated UI tests. Each test can get a fresh instance of the browser, with no browser state, plugin variations or automated browser upgrades to worry about. And you get a video recording of each test session, or just each session where tests failed.
  • Much more! Check out the various contributed modules or create your own custom container classes using GenericContainer as a base.

Prerequisites

Maven dependencies

Testcontainers is distributed as separate JARs with a common version number:

  • A core JAR file for core functionality, generic containers and docker-compose support
  • A separate JAR file for each of the specialised modules. Each module's documentation describes the Maven/Gradle dependency to add to your project's build.

For the core library, the latest Maven/Gradle dependency is as follows:

GradleMaven

testImplementation

"org.testcontainers:testcontainers:1.19.7"

<dependency>

<groupId>

org.testcontainers

</groupId>

<artifactId>

testcontainers

</artifactId>

<version>

1.19.7

</version>

<scope>

test

</scope>

</dependency>

You can also check the latest version available on Maven Central.

Managing versions for multiple Testcontainers dependencies

To avoid specifying the version of each dependency, you can use a BOM or Bill Of Materials.

Using Maven you can add the following to dependencyManagement section in your pom.xml:

Recommended article:
Spectrum Analyzer RBW and VBW

With competitive price and timely delivery, Cell Instruments sincerely hope to be your supplier and partner.

Maven

<dependencyManagement>

<dependencies>

<dependency>

<groupId>

org.testcontainers

</groupId>

<artifactId>

testcontainers-bom

</artifactId>

<version>

1.19.7

</version>

<type>

pom

</type>

<scope>

import

</scope>

</dependency>

</dependencies>

</dependencyManagement>

and then use dependencies without specifying a version:

Maven

<dependency>

<groupId>

org.testcontainers

</groupId>

<artifactId>

mysql

</artifactId>

<scope>

test

</scope>

</dependency>

Using Gradle 5.0 or higher, you can add the following to the dependencies section in your build.gradle:

Gradle

implementation

platform

(

'org.testcontainers:testcontainers-bom:1.19.7'

)

//import bom

testImplementation

(

'org.testcontainers:mysql'

)

//no version specified

JitPack builds are available for pre-release versions.

Shaded dependencies

Testcontainers depends on other libraries (like docker-java) for it to work.
Some of them (JUnit, docker-java-{api,transport} and its transitive dependencies, JNA, visible-assertions and others) are part of our public API.
But there are also "private", implementation detail dependencies (e.g., docker-java-core, Guava, OkHttp, etc.) that are not exposed to public API but prone to conflicts with test code/application under test code. As such, these libraries are 'shaded' into the core Testcontainers JAR and relocated under org.testcontainers.shaded to prevent class conflicts.

A huge thank you to our sponsors:

Donors

Backers

Who is using Testcontainers?

License

See LICENSE.

Attributions

This project includes a modified class (ScriptUtils) taken from the Spring JDBC project, adapted under the terms of the Apache license. Copyright for that class remains with the original authors.

This project was initially inspired by a gist by Moshe Eshel.

Copyright (c) 2015-2021 Richard North and other authors.

See AUTHORS for contributors.

If you are looking for more details, kindly visit Container Tester.

Comments

0/2000

Guest Posts

If you are interested in sending in a Guest Blogger Submission,welcome to write for us!

Your Name: (required)

Your Email: (required)

Subject

Your Message: (required)

0/2000