Making Testing Easier with Testcontainers
Testing is getting easier. Today, it’s about testing fast and often. Iterate to achieve that desired state. And doing it in a way that fits with what DevOps should do — help developers get the flow going.
The open source framework abstracts the Docker API to provide a near-native experience that allows developers to test with dependencies from local environments. Developers insert code to create instances for, as Oleg Selajev, an AtomicJar developer advocate, put it in a recent report, “just about anything that can fit in a container.”
With this approach, several opportunities open for the developer, operations team, and the overall platform engineering team. At its most basic, Testcontainers abstracts the complexity of using containers. Configurations get abstracted. Ops teams don’t have to set up mock environments; platform teams benefit from usage and metrics, governance, and synergy with the developer’s focus on inner loop development.
“Even though we’ve been in this journey of DevOps for the last decade or so, when you talk to platform teams, when you talk to people from those organizations, one of the things that you hear quite frequently is this idea that people need both control and what’s called ‘self serve,'” said Eli Aleyner, co-founder of AtomicJar.
“And when I put this together, I’m like, ‘Why are Testcontainers getting so much adoption?’ I actually feel it’s exactly those trends because developers are able to bring in this library into the codebase without anyone’s permission, without anyone okaying this or doing anything and they get instant productivity, and instant feedback, and be able to iterate faster in the inner development.”
Testcontainers modules come preconfigured, allowing developers to configure in code instead of YAML. Although initially used for testing Java, developers now use Testcontainers for C++, Go, Python, Rust and multiple other programming languages.
The benefits for developers come with the feedback cycles, allowing them to test against dependencies in a local environment, allowing a parallel work environment, and putting developers in a flow. It gets to an issue developers have fought for years: the wait to integrate with shared developer environments, where changes developers make often collide.
“Instead of a testing team, testing starts where the developers are, and just expands what they can do,” Egorov said.
Code over YAML
The libraries in Testcontainers target the Docker API. Instead of YAML, Testcontainers uses domain-specific languages (DSL). In the context of Testcontainers, the library provides the custom languages or APIs that the developer uses to configure and manage containers. The DSL comes embedded within the programming language.
For the developer, using the DSL keeps everything programmatic. This approach abstracts a lot of complexity. For example, developers write new MySQLContainer() instead of specifying implementations such as Docker images, ports, volumes, etc.
Tests and application code get the developer’s full attention. Docker’s intricacies don’t require consideration. Defining and running containers becomes native to the code. It no longer feels like an orchestration concern.
For example, when a platform migrates to a cloud service, the operations team usually needs to provision the shared environment. Testcontainers allow the developer to emulate the environments locally without requiring access to the service. Developers can start working immediately without waiting for the ops team to set up the shared environments.
What’s the DevOps dream? It’s the synergy and harmony with the inner and outer loop. For so long, the ops team did all the set-up and mock-ups while the developer team waited. AtomicJar’s test, no pun intended, will be how well it executes as a tools provider. It faces plenty of competition with the likes of IBM, Parasoft, and SmartBear, just a few of its peers.